home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / adatutor / csparts / cspartb1.src < prev    next >
Text File  |  1996-01-30  |  172KB  |  4,535 lines

  1. --::::::::::
  2. --types.bdy
  3. --::::::::::
  4. -- ***************************************************
  5. -- *                                                 *
  6. -- *  CS_Parts_Types                                 *  BODY
  7. -- *                                                 *
  8. -- ***************************************************
  9. with Unchecked_Conversion;
  10. package body CS_Parts_Types is
  11. --| Notes (none)
  12.  
  13.   function To_Character is new Unchecked_Conversion
  14.     (Source => BYTE, Target => CHARACTER);
  15.  
  16.   function From_Character is new Unchecked_Conversion
  17.     (Source => CHARACTER, Target => BYTE);
  18.  
  19.   -- ...................................................
  20.   -- .                                                 .
  21.   -- .  CS_Parts_Types.Convert                         .  BODY
  22.   -- .                                                 .
  23.   -- ...................................................
  24.   function Convert (Item : in CHARACTER) return BYTE is
  25.   --| Notes (none)
  26.   begin
  27.     return From_Character (Item);
  28.   end Convert;
  29.  
  30.   -- ...................................................
  31.   -- .                                                 .
  32.   -- .  CS_Parts_Types.Convert                         .  BODY
  33.   -- .                                                 .
  34.   -- ...................................................
  35.   function Convert (Item : in INTEGER) return BYTE is
  36.   --| Notes (none)
  37.     I1 : INTEGER := Item;
  38.     I2 : INTEGER := 0;
  39.   begin
  40.     for I in 1..8 loop
  41.       I2 := (I2 * 2) + (I1 - (I1 / 2 * 2));
  42.       I1 := I1/2;
  43.     end loop;
  44.     return BYTE(I2);
  45.   end Convert;
  46.  
  47.   -- ...................................................
  48.   -- .                                                 .
  49.   -- .  CS_Parts_Types.Convert                         .  BODY
  50.   -- .                                                 .
  51.   -- ...................................................
  52.   function Convert (Item : in BYTE) return CHARACTER is
  53.   --| Notes (none)
  54.     CH : CHARACTER;
  55.   begin
  56.     if Item > 127 then
  57.       CH := To_Character (Item - (Item / 128 * 128));
  58.     else
  59.       CH := To_Character (Item);
  60.     end if;
  61.     return CH;
  62.   end Convert;
  63.  
  64.   -- ...................................................
  65.   -- .                                                 .
  66.   -- .  CS_Parts_Types.Convert                         .  SPEC
  67.   -- .                                                 .
  68.   -- ...................................................
  69.   function Convert (Item : in BYTE) return INTEGER is
  70.   --| Notes (none)
  71.   begin
  72.     return INTEGER(Item);
  73.   end Convert;
  74.  
  75. end CS_Parts_Types;
  76. --::::::::::
  77. --console.bdy
  78. --::::::::::
  79. -- *********************************************************
  80. -- *                                                       *
  81. -- *  Console                                              *  BODY
  82. -- *                                                       *
  83. -- *********************************************************
  84. with Text_IO;
  85. with Unchecked_Conversion;
  86. package body Console is
  87. --| Notes (none)
  88.  
  89.   type STATE is (DISABLED, ENABLED);
  90.  
  91.   Output_State : array (1..Max_Number_of_States) of STATE
  92.     := (others => ENABLED);
  93.  
  94.   Current_State : NATURAL := 1;
  95.  
  96.   Terminal : TERMINAL_KIND := TTY;
  97.  
  98.   package INTIO is new TEXT_IO.INTEGER_IO(INTEGER);
  99.   package FLTIO is new TEXT_IO.FLOAT_IO(FLOAT);
  100.  
  101.   function Rend_to_Int is new Unchecked_Conversion (RENDITION,
  102.                                                     INTEGER);
  103.  
  104.   -- .................................................................
  105.   -- .                                                               .
  106.   -- .  Console.Set_Terminal                                         .  BODY
  107.   -- .                                                               .
  108.   -- .................................................................
  109.   procedure Set_Terminal (New_Setting : in TERMINAL_KIND := TTY) is
  110.   --| Notes (none)
  111.   begin
  112.     Terminal := New_Setting;
  113.   end Set_Terminal;
  114.  
  115.   -- .................................................................
  116.   -- .                                                               .
  117.   -- .  Console.Enable_Output                                        .  BODY
  118.   -- .                                                               .
  119.   -- .................................................................
  120.   procedure Enable_Output is
  121.   --| Notes (none)
  122.   begin
  123.     Output_State(Current_State) := ENABLED;
  124.   end Enable_Output;
  125.  
  126.   -- .................................................................
  127.   -- .                                                               .
  128.   -- .  Console.Disable_Output                                       .  BODY
  129.   -- .                                                               .
  130.   -- .................................................................
  131.   procedure Disable_Output is
  132.   --| Notes (none)
  133.   begin
  134.     Output_State(Current_State) := DISABLED;
  135.   end Disable_Output;
  136.  
  137.   -- .................................................................
  138.   -- .                                                               .
  139.   -- .  Console.Push                                                 .  BODY
  140.   -- .                                                               .
  141.   -- .................................................................
  142.   procedure Push is
  143.   --| Notes (none)
  144.   begin
  145.     if Current_State = Max_Number_of_States then
  146.       raise STATE_OVERFLOW;
  147.     else
  148.       Current_State := Current_State + 1;
  149.     end if;
  150.   end Push;
  151.  
  152.   -- .................................................................
  153.   -- .                                                               .
  154.   -- .  Console.Pop                                                  .  BODY   
  155.   -- .                                                               .
  156.   -- .................................................................
  157.   procedure Pop is
  158.   --| Notes (none)
  159.   begin
  160.     if Current_State = Output_State'FIRST then
  161.       raise STATE_UNDERFLOW;
  162.     else
  163.       Current_State := Current_State - 1;
  164.     end if;
  165.   end Pop;
  166.  
  167.   -- .................................................................
  168.   -- .                                                               .
  169.   -- .  Console.Position_Cursor                                      .  BODY
  170.   -- .                                                               .
  171.   -- .................................................................
  172.   procedure Position_Cursor (Row    : in ROW_NUMBER;
  173.                              Column : in COLUMN_NUMBER) is
  174.   --| Notes (none)
  175.   begin
  176.     if (Terminal /= TTY) and (Output_State(Current_State) = ENABLED) then
  177.       Text_IO.Put (ASCII.ESC & "[");
  178.       INTIO.Put (INTEGER(Row), 0);
  179.       Text_IO.Put (';');
  180.       INTIO.Put (INTEGER(Column), 0);
  181.       Text_IO.Put ('H');
  182.     end if;
  183.   end Position_Cursor;
  184.  
  185.   -- .................................................................
  186.   -- .                                                               .
  187.   -- .  Console.Erase_Display                                        .  BODY
  188.   -- .                                                               .
  189.   -- .................................................................
  190.   procedure Erase_Display is
  191.   --| Notes (none)
  192.   begin
  193.     if (Terminal /= TTY) and (Output_State(Current_State) = ENABLED) then
  194.       Text_IO.Put (ASCII.ESC & "[2J");
  195.     end if;
  196.   end Erase_Display;
  197.  
  198.   -- .................................................................
  199.   -- .                                                               .
  200.   -- .  Console.Erase_Line                                           .  BODY
  201.   -- .                                                               .
  202.   -- .................................................................
  203.   procedure Erase_Line is
  204.   --| Notes (none)
  205.   begin
  206.     if (Terminal /= TTY) and (Output_State(Current_State) = ENABLED) then
  207.       Text_IO.Put (ASCII.ESC & "[K");
  208.     end if;
  209.   end Erase_Line;
  210.  
  211.   -- .................................................................
  212.   -- .                                                               .
  213.   -- .  Console.Set_Rendition                                        .  BODY
  214.   -- .                                                               .
  215.   -- .................................................................
  216.   procedure Set_Rendition (New_Setting : in RENDITION) is
  217.   --| Notes
  218.   --|   If the value of Terminal is VT100, no action is taken for any
  219.   --| of the color renditions.
  220.   begin
  221.     if Output_State(Current_State) = ENABLED then
  222.       case New_Setting is
  223.         when ALL_ATTRIBUTES_OFF =>
  224.           if Terminal = ANSI then
  225.             Text_IO.Put (ASCII.ESC & "[0m");
  226.           elsif Terminal = VT100 then
  227.             Text_IO.Put (ASCII.ESC & "[m");
  228.           end if;
  229.         when HIGH_INTENSITY | BLINKING | REVERSE_VIDEO =>
  230.           if Terminal /= TTY then
  231.             Text_IO.Put (ASCII.ESC & "[");
  232.             INTIO.Put (Rend_to_Int(New_Setting), 0);
  233.             Text_IO.Put ('m');
  234.           end if;
  235.         when others =>
  236.           if Terminal = ANSI then
  237.             Text_IO.Put (ASCII.ESC & "[");
  238.             INTIO.Put (Rend_to_Int(New_Setting), 0);
  239.             Text_IO.Put ('m');
  240.           end if;
  241.       end case;
  242.     end if;
  243.   end Set_Rendition;
  244.  
  245.   -- .................................................................
  246.   -- .                                                               .
  247.   -- .  Console.Put                                                  .  BODY
  248.   -- .                                                               .
  249.   -- .................................................................
  250.   procedure Put (Item : in CHARACTER) is
  251.   --| Notes (none)
  252.   begin
  253.     if Output_State(Current_State) = ENABLED then
  254.       Text_IO.Put (Item);
  255.     end if;
  256.   end Put;
  257.  
  258.   -- .................................................................
  259.   -- .                                                               .
  260.   -- .  Console.Put                                                  .  BODY
  261.   -- .                                                               .
  262.   -- .................................................................
  263.   procedure Put (Item : in STRING) is
  264.   --| Notes (none)
  265.   begin
  266.     if Output_State(Current_State) = ENABLED then
  267.       Text_IO.Put (Item);
  268.     end if;
  269.   end Put;
  270.  
  271.   -- .................................................................
  272.   -- .                                                               .
  273.   -- .  Console.Put                                                  .  BODY
  274.   -- .                                                               .
  275.   -- .................................................................
  276.   procedure Put
  277.     ( Item           : in STRING;
  278.       Field_Width    : in NATURAL;
  279.       On_Overflow    : in OVERFLOW_ACTION := TRUNCATE_TAIL;
  280.       On_Underflow   : in JUSTIFICATION   := LEFT_JUSTIFIED;
  281.       Fill_Char      : in CHARACTER       := ' ';
  282.       Overflow_Char  : in CHARACTER       := '*' ) is
  283.   --| Notes (none)
  284.     First_Char  : NATURAL := Item'first;
  285.     Last_Char   : NATURAL := Item'last;
  286.     Fill_Width  : NATURAL;
  287.   begin
  288.     if Output_State(Current_State) = ENABLED then
  289.       if Item'length > Field_Width then
  290.         case On_Overflow is
  291.           when TRUNCATE_TAIL           =>
  292.             Last_Char  := First_Char + Field_Width - 1;
  293.             Text_IO.Put (Item(First_Char .. Last_Char));
  294.           when TRUNCATE_HEAD           =>
  295.             First_Char := Last_Char - Field_Width + 1;
  296.             Text_IO.Put (Item(First_Char .. Last_Char));
  297.           when FILL_WITH_OVERFLOW_CHAR =>
  298.             for I in 1 .. Field_Width loop
  299.               Text_IO.Put (Overflow_Char);
  300.             end loop;
  301.         end case;
  302.       elsif Item'length < Field_Width then
  303.         Fill_Width := Field_Width - Item'length;
  304.         case On_Underflow is
  305.           when LEFT_JUSTIFIED  =>
  306.             Text_IO.Put (Item);
  307.             for I in 1 .. Fill_Width loop
  308.               Text_IO.Put (Fill_Char);
  309.             end loop;
  310.           when RIGHT_JUSTIFIED =>
  311.             for I in 1 .. Fill_Width loop
  312.               Text_IO.Put (Fill_Char);
  313.             end loop;
  314.             Text_IO.Put (Item);
  315.         end case;
  316.       else
  317.         Text_IO.Put (Item);
  318.       end if;
  319.     end if;
  320.   end Put;
  321.  
  322.   -- .................................................................
  323.   -- .                                                               .
  324.   -- .  Console.Put                                                  .  BODY
  325.   -- .                                                               .
  326.   -- .................................................................
  327.   procedure Put (Item          : in INTEGER;
  328.                  Width         : in NATURAL;
  329.                  On_Overflow   : in NUMERIC_OVERFLOW_ACTION
  330.                                    := FILL_WITH_OVERFLOW_CHAR;
  331.                  Overflow_Char : in CHARACTER := '*') is
  332.   --| Notes (none)
  333.     Overflow : BOOLEAN := FALSE;
  334.   begin
  335.     if Output_State(Current_State) = ENABLED then
  336.       begin
  337.         if Width = 0 then
  338.           Overflow := TRUE;
  339.         else
  340.           if Item < 0 then
  341.             if Item <= -10**(Width-1) then
  342.               Overflow := TRUE;
  343.             end if;
  344.           else
  345.             if Item >= 10**Width then
  346.               Overflow := TRUE;
  347.             end if;
  348.           end if;
  349.         end if;
  350.       exception
  351.         when others =>
  352.           Overflow := FALSE;
  353.       end;
  354.       if not Overflow then
  355.         INTIO.Put (Item, Width);
  356.       else -- Overflow
  357.         case On_Overflow is
  358.           when FILL_WITH_OVERFLOW_CHAR =>
  359.             for I in 1 .. Width loop
  360.               Text_IO.Put (Overflow_Char);
  361.             end loop;
  362.           when OUTPUT_FULL_NUMBER             =>
  363.             INTIO.Put (Item, Width);
  364.         end case;
  365.       end if;
  366.     end if;
  367.   end Put;
  368.  
  369.   -- .................................................................
  370.   -- .                                                               .
  371.   -- .  Console.Put                                                  .  BODY
  372.   -- .                                                               .
  373.   -- .................................................................
  374.   procedure Put (Item          : in FLOAT;
  375.                  Fore          : in NATURAL;
  376.                  Aft           : in NATURAL;
  377.                  On_Overflow   : in NUMERIC_OVERFLOW_ACTION
  378.                                    := FILL_WITH_OVERFLOW_CHAR;
  379.                  Overflow_Char : in CHARACTER := '*') is
  380.   --| Notes (none)
  381.     Overflow : BOOLEAN := FALSE;
  382.   begin
  383.     if Output_State(Current_State) = ENABLED then
  384.       begin
  385.         if Fore = 0 then
  386.           Overflow := TRUE;
  387.         else
  388.           if Item < 0.0 then
  389.             if Item <= -10.0**(Fore-1) then
  390.               Overflow := TRUE;
  391.             end if;
  392.           else
  393.             if Item >= 10.0**Fore then
  394.               Overflow := TRUE;
  395.             end if;
  396.           end if;
  397.         end if;
  398.       exception
  399.         when others =>
  400.           Overflow := FALSE;
  401.       end;
  402.       if not Overflow then
  403.         FLTIO.Put (Item, Fore, Aft, 0);
  404.       else -- Overflow
  405.         case On_Overflow is
  406.           when FILL_WITH_OVERFLOW_CHAR =>
  407.             for I in 1 .. Fore loop
  408.               Text_IO.Put (Overflow_Char);
  409.             end loop;
  410.             Text_IO.Put (Overflow_Char); -- decimal
  411.             for I in 1 .. Aft loop
  412.               Text_IO.Put (Overflow_Char);
  413.             end loop;
  414.           when OUTPUT_FULL_NUMBER             =>
  415.             FLTIO.Put (Item, Fore, Aft, 0);
  416.         end case;
  417.       end if;
  418.     end if;
  419.   end Put;
  420.  
  421.   -- .................................................................
  422.   -- .                                                               .
  423.   -- .  Console.Put                                                  .  BODY
  424.   -- .                                                               .
  425.   -- .................................................................
  426.   procedure Put (Item : in FLOAT;
  427.                  Fore : in NATURAL := 2;
  428.                  Aft  : in NATURAL := 2;
  429.                  Exp  : in NATURAL := 3) is
  430.   --| Notes (none)
  431.   begin
  432.     if Output_State(Current_State) = ENABLED then
  433.       FLTIO.Put (Item, Fore, Aft, Exp);
  434.     end if;
  435.   end Put;
  436.  
  437.   -- .................................................................
  438.   -- .                                                               .
  439.   -- .  Console.Put_Line                                             .  BODY
  440.   -- .                                                               .
  441.   -- .................................................................
  442.   procedure Put_Line (Item : in STRING) is
  443.   --| Notes (none)
  444.   begin
  445.     if Output_State(Current_State) = ENABLED then
  446.       Text_IO.Put_Line (Item);
  447.     end if;
  448.   end Put_Line;
  449.  
  450.   -- .................................................................
  451.   -- .                                                               .
  452.   -- .  Console.New_Line                                             .  BODY
  453.   -- .                                                               .
  454.   -- .................................................................
  455.   procedure New_Line is
  456.   --| Notes (none)
  457.   begin
  458.     if Output_State(Current_State) = ENABLED then
  459.       Text_IO.New_Line;
  460.     end if;
  461.   end New_Line;
  462.  
  463.   -- .................................................................
  464.   -- .                                                               .
  465.   -- .  Console.Get                                                  .  BODY
  466.   -- .                                                               .
  467.   -- .................................................................
  468.   procedure Get
  469.     ( Item             : out CHARACTER ) is
  470.   --| Notes (none)
  471.   begin -- Get
  472.     Text_IO.Get (Item);
  473.   exception
  474.     when others =>
  475.       raise INPUT_ERROR;
  476.   end Get;
  477.  
  478.   -- .................................................................
  479.   -- .                                                               .
  480.   -- .  Console.Get                                                  .  BODY
  481.   -- .                                                               .
  482.   -- .................................................................
  483.   procedure Get
  484.     ( Item             : out INTEGER ) is
  485.   --| Notes (none)
  486.   begin -- Get
  487.     INTIO.Get (Item);
  488.   exception
  489.     when others =>
  490.       raise INPUT_ERROR;
  491.   end Get;
  492.  
  493.   -- .................................................................
  494.   -- .                                                               .
  495.   -- .  Console.Get                                                  .  BODY
  496.   -- .                                                               .
  497.   -- .................................................................
  498.   procedure Get
  499.     ( Item             : out FLOAT ) is
  500.   --| Notes (none)
  501.   begin -- Get
  502.     FLTIO.Get (Item);
  503.   exception
  504.     when others =>
  505.       raise INPUT_ERROR;
  506.   end Get;
  507.  
  508.   -- .................................................................
  509.   -- .                                                               .
  510.   -- .  Console.Get_Line                                             .  BODY
  511.   -- .                                                               .
  512.   -- .................................................................
  513.   procedure Get_Line
  514.     ( Item           : out STRING;
  515.       Last           : out NATURAL ) is
  516.   --| Notes (none)
  517.   begin -- Get_Line
  518.     Text_IO.Get_Line(Item, Last);
  519.   end Get_Line;
  520.  
  521. end Console;
  522. --::::::::::
  523. --bintree.bdy
  524. --::::::::::
  525. with unchecked_deallocation;
  526.  
  527. Package body Binary_Trees_Pkg is
  528. --| Efficient implementation of binary trees.
  529.  
  530.  
  531. ----------------------------------------------------------------------------
  532.             -- Local Operations --
  533. ----------------------------------------------------------------------------
  534.  
  535. procedure Free_Node is 
  536.     new unchecked_deallocation(Node, Node_Ptr);
  537.  
  538. procedure Free_Tree is 
  539.     new unchecked_deallocation(Tree_Header, Tree);
  540.  
  541. procedure Free_Iterator is 
  542.     new unchecked_deallocation(Iterator_Record, Iterator);
  543.  
  544. ----------------------------------------------------------------------------
  545.             -- Visible Operations --
  546. ----------------------------------------------------------------------------
  547.  
  548. Function Create        --| Return an empty tree.
  549.     return Tree is
  550.  
  551. begin
  552.     return new Tree_Header'(0, Null);
  553.  
  554. end Create;
  555.  
  556. ----------------------------------------------------------------------------
  557.  
  558. Procedure Insert_Node(
  559.     V: Value_Type;
  560.     N: in out Node_Ptr;
  561.     Found: out boolean;
  562.     Duplicate: out Value_Type
  563.     ) 
  564. is
  565.     D: integer;
  566.  
  567. begin
  568.     Found := False;
  569.     if N = null then
  570.        N := new Node'(V, Null, Null);
  571.     else
  572.       D := Difference(V, N.Value);
  573.       if D < 0 then
  574.         Insert_Node(V, N.Less, Found, Duplicate);
  575.       elsif D > 0 then
  576.         Insert_Node(V, N.More, Found, Duplicate);
  577.       else
  578.     Found := True;
  579.     Duplicate := N.Value;
  580.       end if;
  581.     end if;
  582. end Insert_Node;
  583.  
  584. Procedure Replace_Node(
  585.     V: Value_Type;
  586.     N: in out Node_Ptr;
  587.     Found: out boolean;
  588.     Duplicate: out Value_Type
  589.     ) 
  590. is
  591.     D: integer;
  592.  
  593. begin
  594.     Found := False;
  595.     if N = null then
  596.        N := new Node'(V, Null, Null);
  597.     else
  598.       D := Difference(V, N.Value);
  599.       if D < 0 then
  600.         Replace_Node(V, N.Less, Found, Duplicate);
  601.       elsif D > 0 then
  602.         Replace_Node(V, N.More, Found, Duplicate);
  603.       else
  604.     Found := True;
  605.     Duplicate := N.Value;
  606.     N.Value := V;
  607.       end if;
  608.     end if;
  609. end Replace_Node;
  610.  
  611.  
  612. Procedure Insert(    --| Insert a value into a tree.
  613.     V: Value_Type;    --| Value to be inserted
  614.     T: Tree        --| Tree to contain the new value
  615.     ) --| Raises: Duplicate_Value, Invalid_Tree.
  616. is
  617.     Found: boolean;
  618.     Duplicate: Value_Type;
  619.  
  620. begin
  621.     if T = null then
  622.     raise Invalid_Tree;
  623.     end if;
  624.     Insert_Node(V, T.Root, Found, Duplicate);
  625.     if Found then
  626.         raise Duplicate_Value;
  627.     end if;
  628.     T.Count := T.Count + 1;
  629. end Insert;
  630.  
  631.  
  632. Procedure Insert_if_not_Found(
  633. --| Insert a value into a tree, provided a duplicate value is not already there
  634.     V: Value_Type;    --| Value to be inserted
  635.     T: Tree;        --| Tree to contain the new value
  636.     Found: out boolean;
  637.     Duplicate: out Value_Type
  638.     ) --| Raises: Invalid_Tree.
  639. is
  640.     was_Found: boolean;
  641.  
  642. begin
  643.     if T = null then
  644.     raise Invalid_Tree;
  645.     end if;
  646.     Insert_Node(V, T.Root, was_Found, Duplicate);
  647.     Found := was_Found;
  648.     if not was_Found then
  649.     T.Count := T.Count + 1;
  650.     end if;
  651.  
  652. end Insert_if_Not_Found;
  653.  
  654. procedure Replace_if_Found(
  655. --| Replace a value if label exists, otherwise insert it.
  656.     V: Value_Type;    --| Value to be inserted
  657.     T: Tree;        --| Tree to contain the new value
  658.     Found: out boolean;    --| Becomes True iff L already in tree
  659.     Old_Value: out Value_Type    --| the duplicate value, if there is one
  660.     ) --| Raises: Invalid_Tree.
  661.  
  662. is
  663.     was_Found: boolean;
  664.     Duplicate: Value_Type;
  665.  
  666. begin
  667.     if T = null then
  668.     raise Invalid_Tree;
  669.     end if;
  670.     Replace_Node(V, T.Root, was_Found, Duplicate);
  671.     Found := was_Found;
  672.     if was_Found then
  673.     Old_Value := Duplicate;
  674.     else
  675.     T.Count := T.Count + 1;
  676.     end if;
  677.  
  678. end Replace_if_Found;
  679.  
  680. ----------------------------------------------------------------------------
  681.  
  682. procedure Destroy_Nodes(
  683.     N: in out Node_Ptr
  684.     ) is
  685. begin
  686.     if N /= null then
  687.         Destroy_Nodes(N.Less);
  688.         Destroy_Nodes(N.More);
  689.         Free_Node(N);
  690.     end if;
  691. end Destroy_Nodes;
  692.  
  693. procedure Destroy(    --| Free space allocated to a tree.
  694.     T: in out Tree    --| The tree to be reclaimed.
  695.     ) is
  696.  
  697. begin
  698.     if T /= Null then
  699.       Destroy_Nodes(T.Root);
  700.       Free_Tree(T);
  701.     end if;
  702.  
  703. end Destroy;
  704.  
  705. ----------------------------------------------------------------------------
  706.  
  707. procedure Destroy_Deep(    --| Free all space allocated to a tree.
  708.     T: in out Tree    --| The tree to be reclaimed.
  709.     )
  710. is
  711.     procedure Destroy_Nodes(
  712.     N: in out node_Ptr
  713.     ) is
  714.     begin
  715.     if N /= null then
  716.         Free_Value(N.Value);
  717.             Destroy_Nodes(N.Less);
  718.         Destroy_Nodes(N.More);
  719.         Free_Node(N);
  720.     end if;
  721.     end Destroy_Nodes;
  722.  
  723. begin
  724.     if T /= Null then
  725.       Destroy_Nodes(T.Root);
  726.       Free_Tree(T);
  727.     end if;
  728.  
  729. end Destroy_Deep;
  730.  
  731. ----------------------------------------------------------------------------
  732.  
  733. Function Balanced_Tree(    
  734.     Count: natural
  735.     ) return Tree
  736.  
  737. is
  738.     new_Tree: Tree := Create;
  739.  
  740.     procedure subtree(Count: natural; N: in out Node_Ptr)
  741.     is
  742.     new_Node: Node_Ptr;
  743.  
  744.     begin
  745.     if Count = 1 then
  746.       new_Node := new Node'(next_Value, Null, Null);
  747.     elsif Count > 1 then
  748.       new_node := new Node;
  749.       subtree(Count/2, new_Node.Less);        -- Half are less
  750.       new_Node.Value := next_Value;            -- Median value
  751.       subtree(Count - Count/2 - 1, new_Node.More);    -- Other half are more
  752.     end if;
  753.     N := new_Node;
  754.     end subtree;
  755.  
  756. begin
  757.     new_Tree.Count := Count;
  758.     subtree(Count, new_Tree.Root);
  759.     return new_Tree;
  760.  
  761. end Balanced_Tree;
  762.  
  763. ----------------------------------------------------------------------------
  764.  
  765. Function Copy_Tree(
  766.     T: Tree
  767.     ) return Tree
  768. is
  769.     I: Iterator;
  770.  
  771.     function next_Val return Value_type 
  772.     is
  773.     V: Value_Type;
  774.  
  775.     begin
  776.     Next(I, V);
  777.     return copy_Value(V);
  778.     end next_Val;
  779.  
  780.     function copy_Balanced is new Balanced_Tree(next_Val);
  781.  
  782. begin
  783.     I := Make_Iter(T);    -- Will raise Invalid_Tree if necessary
  784.     return copy_Balanced(Size(T));
  785.  
  786. end Copy_Tree;
  787.  
  788. ----------------------------------------------------------------------------
  789.  
  790. Function Is_Empty(    --| Check for an empty tree.
  791.     T: Tree
  792.     ) return boolean is
  793. begin
  794.     return T = Null or else T.Root = Null;
  795.  
  796. end Is_Empty;
  797.  
  798. ----------------------------------------------------------------------------
  799.  
  800. procedure Find_Node(
  801.     V: Value_Type;        --| Value to be located
  802.     N: Node_Ptr;        --| subtree to be searched
  803.     Match: out Value_Type;    --| Matching value found in the tree
  804.     Found: out Boolean        --| TRUE iff a match was found
  805.     )
  806. is
  807.     D: integer;
  808.  
  809. begin
  810.     if N = null then
  811.         Found := False;
  812.     return;
  813.     end if;
  814.     D := Difference(V, N.Value);
  815.     if D < 0 then
  816.         Find_Node(V, N.Less, Match, Found);
  817.     elsif D > 0 then
  818.         Find_Node(V, N.More, Match, Found);
  819.     else
  820.         Match := N.Value;
  821.     Found := TRUE;
  822.     end if;
  823. end Find_Node;
  824.  
  825. Function Find(        --| Search a tree for a value.
  826.     V: Value_Type;    --| Value to be located
  827.     T: Tree        --| Tree to be searched
  828.     ) return Value_Type --| Raises: Not_Found.
  829. is
  830.     Found: Boolean;
  831.     Match: Value_Type;
  832.  
  833. begin
  834.     if T = Null then
  835.     raise Invalid_Tree;
  836.     end if;
  837.     Find_Node(V, T.Root, Match, Found);
  838.     if Found then
  839.     return Match;
  840.     else
  841.     raise Not_Found;
  842.     end if;
  843. end Find;
  844.  
  845. Procedure Find(            --| Search a tree for a value.
  846.     V: Value_Type;        --| Value to be located
  847.     T: Tree;            --| Tree to be searched
  848.     Found: out Boolean;        --| TRUE iff a match was found
  849.     Match: out Value_Type    --| Matching value found in the tree
  850.     ) is
  851. begin
  852.     if T = Null then
  853.     raise Invalid_Tree;
  854.     end if;
  855.     Find_Node(V, T.Root, Match, Found);
  856. end Find;
  857.  
  858. ----------------------------------------------------------------------------
  859.  
  860. function is_Found(    --| Check a tree for a value.
  861.     V: Value_Type;    --| Value to be located
  862.     T: Tree        --| Tree to be searched
  863.     ) return Boolean
  864. is
  865.     Found: Boolean;
  866.     Match: Value_Type;
  867.  
  868. begin
  869.     if T = Null then
  870.     raise Invalid_Tree;
  871.     end if;
  872.     Find_Node(V, T.Root, Match, Found);
  873.     return Found;
  874.  
  875. end is_Found;
  876.  
  877. ----------------------------------------------------------------------------
  878.  
  879. function Size(        --| Return the count of values in T.
  880.     T: Tree        --| a tree
  881.     ) return natural is
  882.  
  883. begin
  884.     if T = Null then
  885.     Return 0;
  886.     else
  887.         Return T.Count;
  888.     end if;
  889.  
  890. end Size;
  891.  
  892. ----------------------------------------------------------------------------
  893.  
  894. procedure Visit(
  895.     T: Tree;
  896.     Order: Scan_Kind
  897.     ) is
  898.  
  899.     procedure visit_Inorder(N: Node_Ptr) is
  900.     begin
  901.     if N.Less /= null then
  902.       visit_Inorder(N.Less);
  903.     end if;
  904.     Process(N.Value);
  905.     if N.More /= null then
  906.       visit_Inorder(N.More);
  907.     end if;
  908.     end visit_Inorder;
  909.  
  910.     procedure visit_preorder(N: Node_Ptr) is
  911.     begin
  912.     Process(N.Value);
  913.     if N.Less /= null then
  914.       visit_preorder(N.Less);
  915.     end if;
  916.     if N.More /= null then
  917.       visit_preorder(N.More);
  918.     end if;
  919.     end visit_preorder;
  920.  
  921.     procedure visit_postorder(N: Node_Ptr) is
  922.     begin
  923.     if N.Less /= null then
  924.       visit_postorder(N.Less);
  925.     end if;
  926.     if N.More /= null then
  927.       visit_postorder(N.More);
  928.     end if;
  929.     Process(N.Value);
  930.     end visit_postorder;
  931.  
  932. begin
  933.     if T = Null then
  934.     raise Invalid_Tree;
  935.     else
  936.       case Order is
  937.     when inorder =>
  938.       Visit_Inorder(T.Root);
  939.     when preorder =>
  940.       Visit_preorder(T.Root);
  941.     when postorder =>
  942.       Visit_postorder(T.Root);
  943.       end case;
  944.     end if;
  945. end Visit;
  946.  
  947. ----------------------------------------------------------------------------
  948.  
  949. function subtree_Iter(    --| Create an iterator over a subtree
  950.     N: Node_Ptr;
  951.     P: Iterator
  952.     ) return Iterator is
  953.  
  954. begin
  955.     if N = Null then
  956.       return new Iterator_Record'(State => Done, Parent => P, subtree => N);
  957.     elsif N.Less = Null then
  958.       return new Iterator_Record'(State => Middle, Parent => P, subtree => N);
  959.     else
  960.       return new Iterator_Record'(State => Left, Parent => P, subtree => N);
  961.     end if;
  962.  
  963. end subtree_Iter;
  964.  
  965. function Make_Iter(    --| Create an iterator over a tree
  966.     T: Tree
  967.     ) return Iterator is
  968.  
  969. begin
  970.     if T = Null then
  971.     raise Invalid_Tree;
  972.     end if;
  973.     return subtree_Iter(T.Root, Null);
  974.  
  975. end Make_Iter;
  976.  
  977. ----------------------------------------------------------------------------
  978.  
  979. function More(        --| Test for exhausted iterator
  980.     I: Iterator        --| The iterator to be tested
  981.     ) return boolean is
  982.  
  983. begin
  984.     if I = Null then
  985.     return False;
  986.     elsif I.Parent = Null then
  987.     return I.State /= Done and I.subtree /= Null;
  988.     elsif I.State = Done then
  989.     return More(I.Parent);
  990.     else 
  991.     return True;
  992.     end if;
  993.  
  994. end More;
  995.  
  996. ----------------------------------------------------------------------------
  997.  
  998. procedure pop_Iterator(
  999.     I: in out Iterator
  1000.     ) 
  1001. is
  1002.     NI: Iterator;
  1003. begin
  1004.     loop
  1005.       NI := I;
  1006.       I := I.Parent;
  1007.       Free_Iterator(NI);
  1008.       exit when I = Null;
  1009.       exit when I.State /= Done;
  1010.     end loop;
  1011. end pop_Iterator;
  1012.  
  1013. procedure Next(        --| Scan the next value in I
  1014.     I: in out Iterator;    --| an active iterator
  1015.     V: out Value_Type    --| Next value scanned
  1016.     ) --| Raises: No_More.
  1017. is
  1018.     NI: Iterator;
  1019.  
  1020. begin
  1021.     if I = Null or I.State = Done then
  1022.     raise No_More;
  1023.     end if;
  1024.     case I.State is
  1025.       when Left =>    -- Return the leftmost value
  1026.     while I.subtree.Less /= Null loop    -- Find leftmost subtree
  1027.       I.State := Middle;    -- Middle is next at this level
  1028.       I := subtree_Iter(I.subtree.Less, I);
  1029.     end loop;
  1030.     V := I.subtree.Value;
  1031.     if I.subtree.More /= Null then    -- There will be more...
  1032.       I.State := Right;        -- ... coming from the right
  1033.     else                -- Nothing else here
  1034.       pop_Iterator(I);        -- Pop up to parent iterator
  1035.     end if;
  1036.       when Middle =>
  1037.     V := I.subtree.Value;
  1038.     if I.subtree.More /= Null then    -- There will be more...
  1039.       I.State := Right;        -- ... coming from the right
  1040.     else                -- Nothing else here so...
  1041.       pop_Iterator(I);        -- ... Pop up to parent iterator
  1042.     end if;
  1043.       when Right =>    -- Return the value on the right
  1044.     I.State := Done;    -- No more at this level
  1045.     I := subtree_Iter(I.subtree.More, I);
  1046.     Next(I, V);
  1047.       when Done =>
  1048.     pop_Iterator(I);
  1049.     Next(I, V);
  1050.     end case;
  1051.  
  1052. end Next;
  1053.  
  1054. ----------------------------------------------------------------------------
  1055.  
  1056.  
  1057. end binary_trees_pkg;
  1058. --::::::::::
  1059. --bit.bdy
  1060. --::::::::::
  1061. package body BIT_FUNCTIONS is
  1062. --
  1063. --  Implementation notes:
  1064. --      this package uses integer arithmetic (mult by 2 and divide by 2)
  1065. --      to accomplish most of the work involved.
  1066. --
  1067. --  The ideal implementation would be similar to the following:
  1068. --
  1069. --      OBJECT : INTEGER;
  1070. --      type BIT_WORD is array (1..16) of BOOLEAN;
  1071. --      pragma PACK (BIT_WORD)
  1072. --      BIT_OBJECT : BIT_WORD;
  1073. --      for BIT_OBJECT use at OBJECT'ADDRESS;
  1074. --
  1075. --      This effectively defined BIT_OBJECT as a bit array, physically
  1076. --      located at the same memory location as OBJECT.  As a bit array,
  1077. --      slices and boolean operations can be used!  Unfortunately,
  1078. --      the DG/Rolm ADE software does not support the address rep spec.
  1079. --
  1080. --
  1081.     WORD_SIZE : constant := 16; -- ASSUME 16 BIT WORDS!
  1082.  
  1083.     function BIT_EXTRACT (ITEM, START_AT, NBITS : INTEGER) return INTEGER is
  1084.         TEMP      : INTEGER;
  1085.         BIT_VALUE : INTEGER;
  1086.         RESULT    : INTEGER;
  1087.     begin
  1088.         TEMP := SHIFT_RIGHT (ITEM, START_AT);
  1089.         BIT_VALUE := (TEMP mod 2 ** NBITS);
  1090.  
  1091.         if BIT_VALUE <= INTEGER'LAST then
  1092.             RESULT := BIT_VALUE;
  1093.         else
  1094.             RESULT := BIT_VALUE - INTEGER'LAST;
  1095.         end if;
  1096.  
  1097.         return RESULT;
  1098.     end BIT_EXTRACT;
  1099.  
  1100.     function UBIT_EXTRACT (ITEM, START_AT, NBITS : INTEGER) return INTEGER is
  1101.         TEMP : INTEGER;
  1102.     begin
  1103.         TEMP := SHIFT_RIGHT (ITEM, START_AT);
  1104.         return TEMP mod (2 ** NBITS);
  1105.     end UBIT_EXTRACT;
  1106.  
  1107.     function BIT_INSERT (THIS_ITEM, NBITS, INTO_ITEM, START_AT : INTEGER)
  1108.                           return INTEGER is
  1109.         ITEM : INTEGER;
  1110.     begin
  1111.         ITEM := THIS_ITEM mod (2 ** NBITS); -- restrict value to size
  1112.         return BIT_REMOVE (INTO_ITEM, START_AT, NBITS) +
  1113.                SHIFT_LEFT (ITEM, START_AT);
  1114.     end BIT_INSERT;
  1115.  
  1116.     function BIT_REMOVE (ITEM, START_AT, NBITS : INTEGER) return INTEGER is
  1117.         KEEP : INTEGER := 0;
  1118.         TEMP : INTEGER;
  1119.     begin
  1120.         if START_AT /= 0 then
  1121.             KEEP := ITEM mod (2 ** START_AT);
  1122.         end if;
  1123.  
  1124.         TEMP := SHIFT_RIGHT (ITEM, START_AT + NBITS);
  1125.         return SHIFT_LEFT (TEMP, START_AT + NBITS) + KEEP;
  1126.     end BIT_REMOVE;
  1127.  
  1128.     function SHIFT_LEFT (ITEM, NBITS : INTEGER) return INTEGER is
  1129.     begin
  1130.         return ITEM * (2 ** NBITS);
  1131.     end SHIFT_LEFT;
  1132.  
  1133.     function SHIFT_RIGHT (ITEM, NBITS : INTEGER) return INTEGER is
  1134.     begin
  1135.         return ITEM / (2 ** NBITS);
  1136.     end SHIFT_RIGHT;
  1137.  
  1138.     function BIT_AND (WORD1, WORD2 : INTEGER) return INTEGER is
  1139.         SPARE1              : INTEGER := WORD1;
  1140.         SPARE2              : INTEGER := WORD2;
  1141.         NEW_WORD            : INTEGER := 0;
  1142.         BIT1, BIT2, NEW_BIT : INTEGER;
  1143.  
  1144.     begin
  1145. --
  1146. --  the approach here to extract a single bit at a time from each
  1147. --  word, and then decide upon the logical property.  The loop
  1148. --  continues until all bits of the word have been considered,
  1149. --  or until the words become zero in the shifting process.
  1150. --
  1151.  
  1152.         for INDEX in 1 .. WORD_SIZE loop
  1153.             exit when SPARE1 = 0 and SPARE2 = 0;
  1154.             BIT1 := SPARE1 mod 2; -- get rightmost bit
  1155.             BIT2 := SPARE2 mod 2;
  1156.  
  1157.             if BIT1 = 1 and BIT2 = 1 then
  1158.                 NEW_BIT := 1;     -- decide upon new bit value
  1159.             else
  1160.                 NEW_BIT := 0;
  1161.             end if;
  1162.  
  1163.             NEW_WORD := NEW_WORD + SHIFT_LEFT (NEW_BIT, INDEX - 1);
  1164.             SPARE1 := SHIFT_RIGHT (SPARE1, 1);
  1165.             SPARE2 := SHIFT_RIGHT (SPARE2, 1);
  1166.         end loop;
  1167.  
  1168.         return NEW_WORD;
  1169.     end BIT_AND;
  1170.  
  1171.     function BIT_OR (WORD1, WORD2 : INTEGER) return INTEGER is
  1172.         SPARE1              : INTEGER := WORD1;
  1173.         SPARE2              : INTEGER := WORD2;
  1174.         NEW_WORD            : INTEGER := 0;
  1175.         BIT1, BIT2, NEW_BIT : INTEGER;
  1176.  
  1177.     begin
  1178. --  processing is identical to BIT_AND, except the logical test is changed
  1179.         for INDEX in 1 .. WORD_SIZE loop
  1180.             exit when SPARE1 = 0 and SPARE2 = 0;
  1181.             BIT1 := SPARE1 mod 2;
  1182.             BIT2 := SPARE2 mod 2;
  1183.  
  1184.             if BIT1 = 1 or BIT2 = 1 then
  1185.                 NEW_BIT := 1;
  1186.             else
  1187.                 NEW_BIT := 0;
  1188.             end if;
  1189.  
  1190.             NEW_WORD := BIT_INSERT (NEW_BIT, 1, NEW_WORD, INDEX - 1);
  1191.             SPARE1 := SHIFT_RIGHT (SPARE1, 1);
  1192.             SPARE2 := SHIFT_RIGHT (SPARE2, 1);
  1193.         end loop;
  1194.  
  1195.         return NEW_WORD;
  1196.     end BIT_OR;
  1197.  
  1198.     function BIT_MASK (NBITS : INTEGER) return INTEGER is
  1199.         RESULT : INTEGER := 0;
  1200.     begin
  1201.         for INDEX in 1 .. NBITS loop
  1202.             RESULT := RESULT * 2 + 1;
  1203.         end loop;
  1204.  
  1205.         return RESULT;
  1206.     end BIT_MASK;
  1207.  
  1208. end BIT_FUNCTIONS;
  1209. --::::::::::
  1210. --bplustre.bdy
  1211. --::::::::::
  1212. with Unchecked_Deallocation;
  1213.  
  1214. package body BP_Tree is
  1215.  
  1216.    --  *************************************************************************************
  1217.    --  **  This software is part of the Clemson University Computer Science Department's  **
  1218.    --  **  Ada Software Repository, and is copyrighted (C) 1989 by Clemson University.    **
  1219.    --  **  Permission to copy without fee all or part of this software is granted,        **
  1220.    --  **  provided that the copies are not made or distributed for direct commercial     **
  1221.    --  **  advantage, and that this copyright notice is not deleted or modified.  To      **
  1222.    --  **  copy otherwise, or to republish, requires a fee and/or specific permission.    **
  1223.    --  **  >> All bug reporters receive a free updated copy once the bug's corrected! <<  ** 
  1224.    --  **  E-mail to: cpscada@citron.cs.clemson.edu or ...!gatech!hubcap!citron!cpscada.  **
  1225.    --  *************************************************************************************
  1226.  
  1227.    ----------------------------------------------------------------------------------------------------------------------------
  1228.    type Internal_Node (Index_Node : Boolean);
  1229.    ----------------------------------------------------------------------------------------------------------------------------
  1230.    type Internal_Node_Pointer is access Internal_Node;       
  1231.    ----------------------------------------------------------------------------------------------------------------------------
  1232.    Maximum_Number_Of_Subtrees_Per_Node : constant := 3;    -- This can be any odd number >= 3...
  1233.                                                            -- Unfortunately, due to limitations of Ada,
  1234.                                                            --   this cannot be made into a generic parameter.
  1235.    ----------------------------------------------------------------------------------------------------------------------------
  1236.    Minimum_Number_Of_Subtrees_Per_Node : constant := (Maximum_Number_Of_Subtrees_Per_Node/ 2) + 1;
  1237.    ----------------------------------------------------------------------------------------------------------------------------
  1238.    Minimum_Subtree_Number : constant := Minimum_Number_Of_Subtrees_Per_Node - 1;
  1239.    ----------------------------------------------------------------------------------------------------------------------------
  1240.    Maximum_Subtree_Number : constant := Maximum_Number_Of_Subtrees_Per_Node - 1;
  1241.    ----------------------------------------------------------------------------------------------------------------------------
  1242.    type Subtrees is range 0..Maximum_Subtree_Number;
  1243.    ----------------------------------------------------------------------------------------------------------------------------
  1244.    type Array_Of_Subtrees is array (Subtrees) of Internal_Node_Pointer;
  1245.    ----------------------------------------------------------------------------------------------------------------------------
  1246.    Maximum_Number_Of_Keys_Per_Node : constant := Maximum_Number_Of_Subtrees_Per_Node - 1;
  1247.    ----------------------------------------------------------------------------------------------------------------------------
  1248.    type Keys is range 1..Maximum_Number_Of_Keys_Per_Node;
  1249.    ----------------------------------------------------------------------------------------------------------------------------
  1250.    type Key_Pointer is access Key_Type;                     
  1251.    ----------------------------------------------------------------------------------------------------------------------------
  1252.    type Array_Of_Keys is array (Keys) of Key_Pointer;
  1253.    ----------------------------------------------------------------------------------------------------------------------------
  1254.    type Internal_Node (Index_Node : Boolean) is 
  1255.       record
  1256.          case Index_Node is
  1257.             when True  => Maximum_Subtree_Index : Subtrees;
  1258.                           Key                   : Array_Of_Keys;
  1259.                           Subtree               : Array_Of_Subtrees;
  1260.  
  1261.             when False => Preceding_Leaf        : Internal_Node_Pointer := null;
  1262.                           Following_Leaf        : Internal_Node_Pointer := null;
  1263.                           Key_Value             : Key_Pointer;
  1264.                           Item_Container        : Non_Key_Item_Container;
  1265.          end case;
  1266.       end record;
  1267.    ----------------------------------------------------------------------------------------------------------------------------
  1268.    type B_Plus_Tree_Descriptor is 
  1269.       record
  1270.          Root_Node             : Internal_Node_Pointer;
  1271.          Current_Leaf          : Internal_Node_Pointer;
  1272.          Minimum_Key           : Key_Pointer;
  1273.          Number_Of_Keys_Stored : Natural;
  1274.       end record;
  1275.    ----------------------------------------------------------------------------------------------------------------------------
  1276.    type Non_Key_Item_Pointer is access Non_Key_Item_Type;
  1277.    ----------------------------------------------------------------------------------------------------------------------------
  1278.    type Type_Of_Deletion is (Key, Non_Key_Object);
  1279.    ----------------------------------------------------------------------------------------------------------------------------
  1280.    Null_Node_Pointer : Internal_Node_Pointer := null;    -- acceptable as an {in out} parameter...
  1281.    Null_Key_Pointer  : Key_Pointer           := null;    -- acceptable as an {in out} parameter...
  1282.    ----------------------------------------------------------------------------------------------------------------------------
  1283.    function Empty (Targeted_B_Plus_Tree : in B_Plus_Tree) return Boolean is
  1284.  
  1285.    begin   -- function Empty
  1286.       return (Targeted_B_Plus_Tree = null);
  1287.    end Empty;
  1288.    ----------------------------------------------------------------------------------------------------------------------------
  1289.    function Number_Of_Keys_Stored (Targeted_B_Plus_Tree : in B_Plus_Tree) return Natural is
  1290.  
  1291.    begin   -- function Number_Of_Keys_Stored
  1292.       if (Targeted_B_Plus_Tree = null) then
  1293.          return 0;
  1294.       else
  1295.          return Targeted_B_Plus_Tree.Number_Of_Keys_Stored;
  1296.       end if;
  1297.    end Number_Of_Keys_Stored;
  1298.    ----------------------------------------------------------------------------------------------------------------------------
  1299.    procedure Exchange (First_Key_Pointer  : in out Key_Pointer;
  1300.                        Second_Key_Pointer : in out Key_Pointer) is
  1301.  
  1302.       Temp_Key_Pointer : Key_Pointer := First_Key_Pointer;
  1303.  
  1304.    begin   -- procedure Exchange
  1305.       First_Key_Pointer  := Second_Key_Pointer;
  1306.       Second_Key_Pointer := Temp_Key_Pointer;
  1307.    end Exchange;
  1308.    ----------------------------------------------------------------------------------------------------------------------------
  1309.    procedure Exchange (First_Internal_Node_Pointer  : in out Internal_Node_Pointer;
  1310.                        Second_Internal_Node_Pointer : in out Internal_Node_Pointer) is
  1311.  
  1312.       Temp_Internal_Node_Pointer : Internal_Node_Pointer := First_Internal_Node_Pointer;
  1313.  
  1314.    begin   -- procedure Exchange
  1315.       First_Internal_Node_Pointer  := Second_Internal_Node_Pointer;
  1316.       Second_Internal_Node_Pointer := Temp_Internal_Node_Pointer;
  1317.    end Exchange;
  1318.    ----------------------------------------------------------------------------------------------------------------------------
  1319.    procedure Exchange (First_B_Plus_Tree  : in out B_Plus_Tree;
  1320.                        Second_B_Plus_Tree : in out B_Plus_Tree) is
  1321.  
  1322.       Temporary_B_Plus_Tree : B_Plus_Tree := First_B_Plus_Tree;
  1323.  
  1324.    begin   -- procedure Exchange
  1325.       First_B_Plus_Tree := Second_B_Plus_Tree;
  1326.       Second_B_Plus_Tree := Temporary_B_Plus_Tree;
  1327.    end Exchange;
  1328.    ----------------------------------------------------------------------------------------------------------------------------
  1329.    function Determine_Path_Of_Descent (Targeted_Index_Node : in Internal_Node_Pointer;
  1330.                                        Key_Value           : in Key_Type                ) return Subtrees is
  1331.  
  1332.       Path_Number : Subtrees := 0;
  1333.  
  1334.    begin   -- function Determine_Path_Of_Descent
  1335.       while (Path_Number < Maximum_Subtree_Number)
  1336.        and then ( Targeted_Index_Node.Key (Keys'Val (Subtrees'Pos (Path_Number) +1) )  /= null ) 
  1337.        and then not Less_Than (Key_Value, Targeted_Index_Node.Key (Keys'Val (Subtrees'Pos(Path_Number)+1)).all) loop
  1338.          Path_Number := Path_Number + 1;
  1339.       end loop;
  1340.       return Path_Number;
  1341.    end Determine_Path_Of_Descent;
  1342.    ----------------------------------------------------------------------------------------------------------------------------
  1343.    procedure Left_Shift (Node_Being_Shifted     : in out Internal_Node_Pointer;
  1344.                          Minimum_Key_In_Subtree : in out Key_Pointer;
  1345.                          Leftmost_Shift_Point   : in     Subtrees;
  1346.                          Rightmost_Shift_Point  : in     Subtrees               ) is
  1347.  
  1348.       -- Assumption: Leftmost_Shift_Point > 0...
  1349.  
  1350.    begin   -- procedure Left_Shift
  1351.       for Subtree_Number in Leftmost_Shift_Point..Rightmost_Shift_Point loop
  1352.          Node_Being_Shifted.Subtree (Subtree_Number - 1) := Node_Being_Shifted.Subtree (Subtree_Number);
  1353.          if (Subtree_Number > 1) then
  1354.             Node_Being_Shifted.Key ( Keys'Val (Subtrees'Pos (Subtree_Number - 1) ) )
  1355.                := Node_Being_Shifted.Key ( Keys'Val (Subtrees'Pos (Subtree_Number) ) );
  1356.          else
  1357.             Minimum_Key_In_Subtree := Node_Being_Shifted.Key ( Keys'Val (Subtrees'Pos (Subtree_Number) ) );
  1358.          end if;
  1359.       end loop;
  1360.    end Left_Shift;
  1361.    ----------------------------------------------------------------------------------------------------------------------------
  1362.    procedure Right_Shift (Node_Being_Shifted     : in out Internal_Node_Pointer;
  1363.                           Minimum_Key_In_Subtree : in out Key_Pointer;
  1364.                           Leftmost_Shift_Point   : in     Subtrees;
  1365.                           Rightmost_Shift_Point  : in     Subtrees               ) is
  1366.  
  1367.       -- Assumption: Rightmost_Shift_Point < Maximum_Subtree_Number...
  1368.  
  1369.    begin   -- procedure Right_Shift
  1370.       for Subtree_Number in reverse Leftmost_Shift_Point..Rightmost_Shift_Point loop
  1371.          Node_Being_Shifted.Subtree (Subtree_Number + 1) := Node_Being_Shifted.Subtree (Subtree_Number);
  1372.          if (Subtree_Number > 0) then
  1373.             Node_Being_Shifted.Key ( Keys'Val (Subtrees'Pos (Subtree_Number + 1) ) )
  1374.                := Node_Being_Shifted.Key ( Keys'Val (Subtrees'Pos (Subtree_Number) ) );
  1375.          else
  1376.             Node_Being_Shifted.Key (1) := Minimum_Key_In_Subtree;
  1377.          end if;
  1378.       end loop;
  1379.    end Right_Shift;
  1380.    ----------------------------------------------------------------------------------------------------------------------------
  1381.    procedure Insert_Extra_Subtree (Targeted_Index_Node          : in out Internal_Node_Pointer;
  1382.                                    Minimum_Key_In_Subtree       : in out Key_Pointer;
  1383.                                    Extra_Subtree                : in out Internal_Node_Pointer;
  1384.                                    Minimum_Key_In_Extra_Subtree : in out Key_Pointer           ) is
  1385.  
  1386.       -- Assumption: Targeted_Index_Node.Maximum_Subtree_Index < Maximum_Subtree_Number...
  1387.  
  1388.       Path_Of_Descent : Subtrees;
  1389.       Insertion_Point : Subtrees;
  1390.  
  1391.    begin   -- procedure Insert_Extra_Subtree
  1392.       Path_Of_Descent := Determine_Path_Of_Descent (Targeted_Index_Node, Minimum_Key_In_Extra_Subtree.all);
  1393.       if (Path_Of_Descent > 0) 
  1394.        or else Less_Than (Minimum_Key_In_Subtree.all, Minimum_Key_In_Extra_Subtree.all) then
  1395.          Insertion_Point := Path_Of_Descent + 1;
  1396.       else
  1397.          Insertion_Point := Path_Of_Descent;
  1398.       end if;
  1399.       Right_Shift (Targeted_Index_Node, Minimum_Key_In_Subtree, Insertion_Point, Targeted_Index_Node.Maximum_Subtree_Index);
  1400.       Targeted_Index_Node.Subtree (Insertion_Point) := Extra_Subtree;
  1401.       if (Insertion_Point = 0) then
  1402.          Minimum_Key_In_Subtree := Minimum_Key_In_Extra_Subtree;
  1403.       else
  1404.          Targeted_Index_Node.Key ( Keys'Val (Subtrees'Pos (Insertion_Point))) := Minimum_Key_In_Extra_Subtree;
  1405.       end if;
  1406.       Targeted_Index_Node.Maximum_Subtree_Index := Targeted_Index_Node.Maximum_Subtree_Index + 1;
  1407.       Extra_Subtree                := null;
  1408.       Minimum_Key_In_Extra_Subtree := null;
  1409.    end Insert_Extra_Subtree;
  1410.    ----------------------------------------------------------------------------------------------------------------------------
  1411.    procedure Delete_Subtree (Targeted_Node          : in out Internal_Node_Pointer;
  1412.                              Minimum_Key_In_Subtree : in out Key_Pointer;
  1413.                              Targeted_Subtree       : in     Subtrees              ) is
  1414.  
  1415.    begin   -- procedure Delete_Subtree
  1416.       if (Targeted_Subtree < Targeted_Node.Maximum_Subtree_Index) then
  1417.          Left_Shift (Targeted_Node, Minimum_Key_In_Subtree, (Targeted_Subtree+1), Targeted_Node.Maximum_Subtree_Index);
  1418.       end if;
  1419.       Targeted_Node.Subtree (Targeted_Node.Maximum_Subtree_Index) := null;
  1420.       if (Targeted_Node.Maximum_Subtree_Index = 0) then
  1421.          Minimum_Key_In_Subtree := null;
  1422.       else
  1423.          Targeted_Node.Key ( Keys'Val ( Subtrees'Pos (Targeted_Node.Maximum_Subtree_Index) ) ) := null;
  1424.          Targeted_Node.Maximum_Subtree_Index := Targeted_Node.Maximum_Subtree_Index - 1;
  1425.       end if;
  1426.    end Delete_Subtree;
  1427.    ----------------------------------------------------------------------------------------------------------------------------
  1428.    procedure Insert_Item (Targeted_B_Plus_Tree : in out B_Plus_Tree;
  1429.                           Key_Value            : in     Key_Type;
  1430.                           Non_Key_Information  : in     Non_Key_Item_Type) is
  1431.  
  1432.  
  1433.       New_Root                     : Internal_Node_Pointer;
  1434.       Extra_Subtree                : Internal_Node_Pointer := null;
  1435.       Minimum_Key_In_Extra_Subtree : Key_Pointer           := null;
  1436.  
  1437.       procedure Generate_New_Leaf (Pointer_To_Preceding_Leaf : in     Internal_Node_Pointer;
  1438.                                    Pointer_To_New_Leaf       : in out Internal_Node_Pointer;
  1439.                                    Pointer_To_Following_Leaf : in     Internal_Node_Pointer;
  1440.                                    Value_Of_New_Key          : in     Key_Type               ) is
  1441.  
  1442.       begin   -- procedure Generate_New_Leaf
  1443.          Pointer_To_New_Leaf := new Internal_Node (Index_Node => False);
  1444.          Pointer_To_New_Leaf.Preceding_Leaf := Pointer_To_Preceding_Leaf;
  1445.          Pointer_To_New_Leaf.Following_Leaf := Pointer_To_Following_Leaf;
  1446.          if (Pointer_To_Preceding_Leaf /= null) then
  1447.             Pointer_To_Preceding_Leaf.Following_Leaf := Pointer_To_New_Leaf;
  1448.          end if;
  1449.          if (Pointer_To_Following_Leaf /= null) then
  1450.             Pointer_To_Following_Leaf.Preceding_Leaf := Pointer_To_New_Leaf;
  1451.          end if;
  1452.          Pointer_To_New_Leaf.Key_Value := new Key_Type;
  1453.          Assign (Pointer_To_New_Leaf.Key_Value.all, Value_Of_New_Key);
  1454.       end Generate_New_Leaf;
  1455.  
  1456.      
  1457.       procedure Create_New_B_Plus_Tree (Targeted_B_Plus_Tree : in out B_Plus_Tree;
  1458.                                         Key_Value            : in     Key_Type;
  1459.                                         Non_Key_Information  : in     Non_Key_Item_Type) is
  1460.  
  1461.       begin   -- procedure Create_New_B_Plus_Tree
  1462.          Targeted_B_Plus_Tree := new B_Plus_Tree_Descriptor;
  1463.          Targeted_B_Plus_Tree.Root_Node := new Internal_Node (Index_Node => True);
  1464.          Generate_New_Leaf (null, Targeted_B_Plus_Tree.Root_Node.Subtree(0), null, Key_Value);
  1465.          Insert (Targeted_B_Plus_Tree.Root_Node.Subtree(0).Item_Container, Non_Key_Information);
  1466.          Targeted_B_Plus_Tree.Current_Leaf := Targeted_B_Plus_Tree.Root_Node.Subtree(0);
  1467.          Targeted_B_Plus_Tree.Minimum_Key := Targeted_B_Plus_Tree.Root_Node.Subtree(0).Key_Value;
  1468.          Targeted_B_Plus_Tree.Root_Node.Maximum_Subtree_Index := 0;
  1469.          Targeted_B_Plus_Tree.Number_Of_Keys_Stored := 1;
  1470.       end Create_New_B_Plus_Tree;
  1471.  
  1472.  
  1473.       procedure Insert_Subtree (Left_Sibling                 : in out Internal_Node_Pointer;
  1474.                                 Minimum_Key_In_Left_Sibling  : in out Key_Pointer;
  1475.                                 Targeted_Index_Node          : in out Internal_Node_Pointer;
  1476.                                 Minimum_Key_In_Subtree       : in out Key_Pointer;
  1477.                                 Right_Sibling                : in out Internal_Node_Pointer;
  1478.                                 Minimum_Key_In_Right_Sibling : in out Key_Pointer;
  1479.                                 Extra_Subtree                : in out Internal_Node_Pointer;
  1480.                                 Minimum_Key_In_Extra_Subtree : in out Key_Pointer            ) is
  1481.  
  1482.  
  1483.          Room_In_Left_Sibling : Boolean := ( (Left_Sibling /= null)
  1484.                                                 and then (Left_Sibling.Index_Node = True)
  1485.                                                     and then (Left_Sibling.Maximum_Subtree_Index < Maximum_Subtree_Number) );
  1486.  
  1487.          Room_In_Right_Sibling : Boolean := ( (Right_Sibling /= null)
  1488.                                                 and then (Right_Sibling.Index_Node = True)
  1489.                                                     and then (Right_Sibling.Maximum_Subtree_Index < Maximum_Subtree_Number) );
  1490.  
  1491.          type Overflow_Preference is (Return_Leftmost_Subtree, Return_Rightmost_Subtree);
  1492.  
  1493.  
  1494.          procedure Insert_And_Overflow (Targeted_Index_Node          : in out Internal_Node_Pointer;
  1495.                                         Minimum_Key_In_Subtree       : in out Key_Pointer;
  1496.                                         Extra_Subtree                : in out Internal_Node_Pointer;
  1497.                                         Minimum_Key_In_Extra_Subtree : in out Key_Pointer;
  1498.                                         Overflow_Directions          : in     Overflow_Preference   ) is
  1499.  
  1500.             Temp_Subtree    : Internal_Node_Pointer;
  1501.             Temp_Key        : Key_Pointer;
  1502.             Insertion_Point : Subtrees := Determine_Path_Of_Descent (Targeted_Index_Node, Minimum_Key_In_Extra_Subtree.all);
  1503.  
  1504.          begin   -- procedure Insert_And_Overflow
  1505.             if (Overflow_Directions = Return_Leftmost_Subtree) then
  1506.                if (Insertion_Point = 0) then
  1507.                   if Less_Than (Minimum_Key_In_Subtree.all, Minimum_Key_In_Extra_Subtree.all) then 
  1508.                      Exchange (Targeted_Index_Node.Subtree(0), Extra_Subtree);
  1509.                      Exchange (Minimum_Key_In_Extra_Subtree, Minimum_Key_In_Subtree);
  1510.                   end if;
  1511.                else
  1512.                   Temp_Subtree := Targeted_Index_Node.Subtree(0);
  1513.                   Temp_Key     := Minimum_Key_In_Subtree;
  1514.                   Left_Shift (Targeted_Index_Node, Minimum_Key_In_Subtree, 1, Insertion_Point);
  1515.                   Targeted_Index_Node.Subtree (Insertion_Point) := Extra_Subtree;
  1516.                   Targeted_Index_Node.Key (Keys'Val(Subtrees'Pos(Insertion_Point))) := Minimum_Key_In_Extra_Subtree;
  1517.                   Extra_Subtree                := Temp_Subtree;
  1518.                   Minimum_Key_In_Extra_Subtree := Temp_Key;
  1519.                end if;
  1520.             elsif (Overflow_Directions = Return_Rightmost_Subtree) then
  1521.                if (Insertion_Point + 1 >= Maximum_Subtree_Number) then
  1522.                   if not Less_Than (Targeted_Index_Node.Key (Maximum_Subtree_Number).all, Minimum_Key_In_Extra_Subtree.all) then
  1523.                      Exchange (Extra_Subtree, Targeted_Index_Node.Subtree (Maximum_Subtree_Number) );
  1524.                      Exchange (Minimum_Key_In_Extra_Subtree, 
  1525.                                      Targeted_Index_Node.Key (Keys'Val (Subtrees'Pos (Maximum_Subtree_Number) ) ) );
  1526.                   end if;
  1527.                else
  1528.                   if not (Insertion_Point = 0) 
  1529.                    or else Less_Than (Minimum_Key_In_Subtree.all, Minimum_Key_In_Extra_Subtree.all) then
  1530.                      Insertion_Point := Insertion_Point + 1;
  1531.                   end if;
  1532.                   Temp_Subtree := Targeted_Index_Node.Subtree (Maximum_Subtree_Number);
  1533.                   Temp_Key     := Targeted_Index_Node.Key (Maximum_Subtree_Number);
  1534.                   Right_Shift (Targeted_Index_Node, Minimum_Key_In_Subtree, Insertion_Point, (Maximum_Subtree_Number - 1));
  1535.                   Targeted_Index_Node.Subtree (Insertion_Point) := Extra_Subtree;
  1536.                   if (Insertion_Point = 0) then
  1537.                      Minimum_Key_In_Subtree := Minimum_Key_In_Extra_Subtree;
  1538.                   else
  1539.                      Targeted_Index_Node.Key ( Keys'Val ( Subtrees'Pos ( Insertion_Point ) ) ) := Minimum_Key_In_Extra_Subtree;
  1540.                   end if;
  1541.                   Extra_Subtree                := Temp_Subtree;
  1542.                   Minimum_Key_In_Extra_Subtree := Temp_Key;
  1543.                end if;
  1544.             end if;
  1545.          end Insert_And_Overflow;
  1546.  
  1547.  
  1548.          procedure Insert_And_Partition (Targeted_Index_Node          : in out Internal_Node_Pointer;
  1549.                                          Minimum_Key_In_Subtree       : in out Key_Pointer;
  1550.                                          Extra_Subtree                : in out Internal_Node_Pointer;
  1551.                                          Minimum_Key_In_Extra_Subtree : in out Key_Pointer            ) is
  1552.  
  1553.             Insertion_Point                  : Subtrees;
  1554.             New_Extra_Subtree                : Internal_Node_Pointer;
  1555.             Minimum_Key_In_New_Extra_Subtree : Key_Pointer;
  1556.  
  1557.             procedure Partition (Targeted_Index_Node              : in out Internal_Node_Pointer;
  1558.                                  Minimum_Key_In_Subtree           : in out Key_Pointer;
  1559.                                  Node_Split_Point                 : in     Subtrees;
  1560.                                  New_Extra_Subtree                : in out Internal_Node_Pointer;
  1561.                                  Minimum_Key_In_New_Extra_Subtree : in out Key_Pointer             ) is
  1562.  
  1563.             begin   -- procedure Partition
  1564.  
  1565.                New_Extra_Subtree := new Internal_Node (Index_Node => True);
  1566.  
  1567.                for Transferred_Subtree_Index in reverse Node_Split_Point..Maximum_Subtree_Number loop
  1568.                   New_Extra_Subtree.Subtree (Transferred_Subtree_Index - Node_Split_Point)
  1569.                      := Targeted_Index_Node.Subtree (Transferred_Subtree_Index);
  1570.                   Targeted_Index_Node.Subtree (Transferred_Subtree_Index) := null;
  1571.                   if (Transferred_Subtree_Index - Node_Split_Point) > 0 then
  1572.                      New_Extra_Subtree.Key (Keys'Val ( Subtrees'Pos (Transferred_Subtree_Index - Node_Split_Point)))
  1573.                         := Targeted_Index_Node.Key (Keys'Val ( Subtrees'Pos (Transferred_Subtree_Index)));
  1574.                   else
  1575.                      Minimum_Key_In_New_Extra_Subtree 
  1576.                         := Targeted_Index_Node.Key (Keys'Val (Subtrees'Pos (Transferred_Subtree_Index) ) );
  1577.                   end if;
  1578.                   Targeted_Index_Node.Key (Keys'Val (Subtrees'Pos (Transferred_Subtree_Index))) := null;
  1579.                end loop;
  1580.  
  1581.                Targeted_Index_Node.Maximum_Subtree_Index := Node_Split_Point - 1;
  1582.  
  1583.                New_Extra_Subtree.Maximum_Subtree_Index := Maximum_Subtree_Number - Node_Split_Point;
  1584.  
  1585.             end Partition;
  1586.  
  1587.          begin     -- procedure Insert_And_Partition
  1588.  
  1589.             Insertion_Point := Determine_Path_Of_Descent (Targeted_Index_Node, Minimum_Key_In_Extra_Subtree.all);
  1590.  
  1591.             if (Insertion_Point < Minimum_Subtree_Number) then
  1592.                Partition (Targeted_Index_Node, Minimum_Key_In_Subtree, Minimum_Subtree_Number, 
  1593.                                                                          New_Extra_Subtree, Minimum_Key_In_New_Extra_Subtree);
  1594.                Insert_Extra_Subtree (Targeted_Index_Node, Minimum_Key_In_Subtree, Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1595.             else
  1596.                Partition (Targeted_Index_Node, Minimum_Key_In_Subtree, Minimum_Subtree_Number + 1, 
  1597.                                                                          New_Extra_Subtree, Minimum_Key_In_New_Extra_Subtree);
  1598.                Insert_Extra_Subtree (New_Extra_Subtree, Minimum_Key_In_New_Extra_Subtree,
  1599.                                                                          Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1600.             end if;
  1601.  
  1602.             Extra_Subtree                := New_Extra_Subtree;
  1603.             Minimum_Key_In_Extra_Subtree := Minimum_Key_In_New_Extra_Subtree;
  1604.  
  1605.          end Insert_And_Partition;
  1606.  
  1607.  
  1608.       begin     -- procedure Insert_Subtree
  1609.          if (Targeted_Index_Node.Maximum_Subtree_Index < Maximum_Subtree_Number) then
  1610.             Insert_Extra_Subtree (Targeted_Index_Node, Minimum_Key_In_Subtree, Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1611.          elsif Room_In_Left_Sibling and not Room_In_Right_Sibling then
  1612.             Insert_And_Overflow (Targeted_Index_Node, Minimum_Key_In_Subtree,
  1613.                                                  Extra_Subtree, Minimum_Key_In_Extra_Subtree, Return_Leftmost_Subtree);
  1614.             Insert_Extra_Subtree (Left_Sibling, Minimum_Key_In_Left_Sibling, Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1615.          elsif Room_In_Right_Sibling then
  1616.             Insert_And_Overflow (Targeted_Index_Node, Minimum_Key_In_Subtree,
  1617.                                                  Extra_Subtree, Minimum_Key_In_Extra_Subtree, Return_Rightmost_Subtree);
  1618.             Insert_Extra_Subtree (Right_Sibling, Minimum_Key_In_Right_Sibling, Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1619.          else
  1620.             Insert_And_Partition (Targeted_Index_Node, Minimum_Key_In_Subtree, Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1621.          end if;
  1622.       end Insert_Subtree;
  1623.  
  1624.  
  1625.       procedure Descend_And_Insert_Leaf (Left_Sibling                 : in     Internal_Node_Pointer;
  1626.                                          Target_Node                  : in     Internal_Node_Pointer;
  1627.                                          Right_Sibling                : in     Internal_Node_Pointer;
  1628.                                          Minimum_Key_In_Subtree       : in out Key_Pointer;
  1629.                                          Extra_Subtree                : in out Internal_Node_Pointer;
  1630.                                          Minimum_Key_In_Extra_Subtree : in out Key_Pointer           ) is
  1631.  
  1632.          Path_Of_Descent : Subtrees;
  1633.  
  1634.       begin   -- procedure Descend_And_Insert_Leaf
  1635.  
  1636.          if (Target_Node.Index_Node = False) then 
  1637.  
  1638.             if Equal (Target_Node.Key_Value.all, Key_Value) then
  1639.  
  1640.                Insert (Target_Node.Item_Container, Non_Key_Information);
  1641.                Targeted_B_Plus_Tree.Current_Leaf := Target_Node;
  1642.  
  1643.             else
  1644.  
  1645.                if Less_Than (Key_Value, Target_Node.Key_Value.all) then
  1646.                   Generate_New_Leaf (Target_Node.Preceding_Leaf, Extra_Subtree, Target_Node, Key_Value);
  1647.                else
  1648.                   Generate_New_Leaf (Target_Node, Extra_Subtree, Target_Node.Following_Leaf, Key_Value);
  1649.                end if;
  1650.  
  1651.                Insert (Extra_Subtree.Item_Container, Non_Key_Information);
  1652.                Minimum_Key_In_Extra_Subtree := Extra_Subtree.Key_Value;
  1653.                Targeted_B_Plus_Tree.Current_Leaf := Extra_Subtree;
  1654.  
  1655.                Targeted_B_Plus_Tree.Number_Of_Keys_Stored := Targeted_B_Plus_Tree.Number_Of_Keys_Stored + 1;
  1656.  
  1657.             end if;
  1658.  
  1659.          else                         
  1660.  
  1661.             Path_Of_Descent := Determine_Path_Of_Descent (Target_Node, Key_Value);
  1662.  
  1663.             case Path_Of_Descent is
  1664.  
  1665.                 when 0 
  1666.                    => Descend_And_Insert_Leaf (Null_Node_Pointer, 
  1667.                                                  Target_Node.Subtree (0), 
  1668.                                                    Target_Node.Subtree (1),
  1669.                                                      Minimum_Key_In_Subtree,
  1670.                                                        Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1671.                      if (Extra_Subtree /= null) 
  1672.                       and (Target_Node.Subtree (Path_Of_Descent).all.Index_Node = True) then
  1673.                         Insert_Subtree (Null_Node_Pointer,
  1674.                                           Null_Key_Pointer,
  1675.                                             Target_Node.Subtree (0),
  1676.                                               Minimum_Key_In_Subtree,
  1677.                                                 Target_Node.Subtree (1),
  1678.                                                   Target_Node.Key (1),
  1679.                                                     Extra_Subtree, Minimum_Key_In_Extra_Subtree); 
  1680.                      end if;
  1681.  
  1682.                when 1..(Maximum_Subtree_Number - 1)
  1683.                   => Descend_And_Insert_Leaf (Target_Node.Subtree (Path_Of_Descent - 1), 
  1684.                                                 Target_Node.Subtree (Path_Of_Descent), 
  1685.                                                   Target_Node.Subtree (Path_Of_Descent + 1),
  1686.                                                     Target_Node.Key ( Keys'Val ( Subtrees'Pos (Path_Of_Descent))),
  1687.                                                       Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1688.                      if (Extra_Subtree /= null) 
  1689.                       and (Target_Node.Subtree (Path_Of_Descent).Index_Node = True) then
  1690.                         if (Path_Of_Descent = 1) then
  1691.                            Insert_Subtree (Target_Node.Subtree (0),
  1692.                                              Minimum_Key_In_Subtree,
  1693.                                                Target_Node.Subtree (1),
  1694.                                                  Target_Node.Key (1),
  1695.                                                    Target_Node.Subtree (2),
  1696.                                                      Target_Node.Key (2),
  1697.                                                        Extra_Subtree, Minimum_Key_In_Extra_Subtree); 
  1698.                         else
  1699.                            Insert_Subtree (Target_Node.Subtree (Path_Of_Descent - 1),
  1700.                                              Target_Node.Key (Keys'Val (Subtrees'Pos (Path_Of_Descent - 1))),
  1701.                                                Target_Node.Subtree (Path_Of_Descent),
  1702.                                                  Target_Node.Key ( Keys'Val ( Subtrees'Pos (Path_Of_Descent))),
  1703.                                                    Target_Node.Subtree (Path_Of_Descent + 1),
  1704.                                                      Target_Node.Key ( Keys'Val (Subtrees'Pos (Path_Of_Descent-1))),
  1705.                                                        Extra_Subtree, Minimum_Key_In_Extra_Subtree); 
  1706.                         end if;
  1707.                      end if;
  1708.  
  1709.                when Maximum_Subtree_Number
  1710.                   => Descend_And_Insert_Leaf (Target_Node.Subtree (Maximum_Subtree_Number - 1), 
  1711.                                                 Target_Node.Subtree (Maximum_Subtree_Number), 
  1712.                                                   Null_Node_Pointer,
  1713.                                                     Target_Node.Key (Maximum_Subtree_Number),
  1714.                                                       Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1715.                      if (Extra_Subtree /= null) 
  1716.                       and (Target_Node.Subtree (Path_Of_Descent).Index_Node = True) then
  1717.                         Insert_Subtree (Target_Node.Subtree (Maximum_Subtree_Number - 1),
  1718.                                           Target_Node.Key (Maximum_Subtree_Number - 1),
  1719.                                             Target_Node.Subtree (Maximum_Subtree_Number),
  1720.                                               Target_Node.Key (Maximum_Subtree_Number),
  1721.                                                 Null_Node_Pointer,
  1722.                                                   Null_Key_Pointer,
  1723.                                                     Extra_Subtree, Minimum_Key_In_Extra_Subtree); 
  1724.                      end if;
  1725.  
  1726.             end case;
  1727.  
  1728.          end if;
  1729.  
  1730.       end Descend_And_Insert_Leaf;
  1731.  
  1732.  
  1733.    begin    -- procedure Insert_Item
  1734.  
  1735.       if (Targeted_B_Plus_Tree = null) then
  1736.  
  1737.          Create_New_B_Plus_Tree (Targeted_B_Plus_Tree, Key_Value, Non_Key_Information);
  1738.  
  1739.       else
  1740.  
  1741.          Descend_And_Insert_Leaf (null, Targeted_B_Plus_Tree.Root_Node, null, 
  1742.                                      Targeted_B_Plus_Tree.Minimum_Key, Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1743.  
  1744.          if (Extra_Subtree /= null) then
  1745.             Insert_Subtree (Null_Node_Pointer, Null_Key_Pointer, 
  1746.                                     Targeted_B_Plus_Tree.Root_Node, Targeted_B_Plus_Tree.Minimum_Key, 
  1747.                                               Null_Node_Pointer, Null_Key_Pointer,
  1748.                                                        Extra_Subtree, Minimum_Key_In_Extra_Subtree);
  1749.          end if;
  1750.  
  1751.          if (Extra_Subtree /= null) then
  1752.             New_Root := new Internal_Node (Index_Node => True);
  1753.             New_Root.Subtree(0) := Targeted_B_Plus_Tree.Root_Node; 
  1754.             New_Root.Subtree(1) := Extra_Subtree;
  1755.             New_Root.Key(1) := Minimum_Key_In_Extra_Subtree;
  1756.             New_Root.Maximum_Subtree_Index := 1;
  1757.             Targeted_B_Plus_Tree.Root_Node := New_Root;
  1758.          end if;
  1759.          
  1760.       end if;
  1761.  
  1762.    end Insert_Item;
  1763.    ----------------------------------------------------------------------------------------------------------------------------
  1764.    procedure Destroy is new Unchecked_Deallocation (Key_Type, Key_Pointer);
  1765.    ----------------------------------------------------------------------------------------------------------------------------
  1766.    procedure Destroy is new Unchecked_Deallocation (Internal_Node, Internal_Node_Pointer);
  1767.    ----------------------------------------------------------------------------------------------------------------------------
  1768.    procedure Annihilate is new Unchecked_Deallocation (B_Plus_Tree_Descriptor, B_Plus_Tree);
  1769.    ----------------------------------------------------------------------------------------------------------------------------
  1770.    procedure Destroy_Subtree (Target_Node : in out Internal_Node_Pointer) is
  1771.  
  1772.    begin   -- procedure Destroy_Subtree
  1773.       if (Target_Node /= null) then 
  1774.          if (Target_Node.Index_Node = False) then
  1775.             if (Target_Node.Preceding_Leaf /= null) then
  1776.                Target_Node.Preceding_Leaf.Following_Leaf := Target_Node.Following_Leaf;
  1777.             end if;
  1778.             if (Target_Node.Following_Leaf /= null) then
  1779.                Target_Node.Following_Leaf.Preceding_Leaf := Target_Node.Preceding_Leaf;
  1780.             end if;
  1781.             Destroy (Target_Node.Key_Value);
  1782.             Destroy_Contents (Target_Node.Item_Container);
  1783.             Destroy (Target_Node);
  1784.          else
  1785.             for Subtree_Number in Subtrees loop
  1786.                Destroy_Subtree (Target_Node.Subtree (Subtree_Number));
  1787.             end loop;
  1788.             Destroy (Target_Node);  
  1789.          end if;
  1790.       end if;
  1791.    end Destroy_Subtree;
  1792.    ----------------------------------------------------------------------------------------------------------------------------
  1793.    procedure Destroy (Targeted_B_Plus_Tree : in out B_Plus_Tree) is
  1794.  
  1795.       -- Destroys all keys and all associated containers, and renders the tree Empty.
  1796.  
  1797.    begin   -- procedure Destroy
  1798.       if not Empty (Targeted_B_Plus_Tree) then
  1799.          Destroy_Subtree (Targeted_B_Plus_Tree.Root_Node);
  1800.          Annihilate (Targeted_B_Plus_Tree);
  1801.       end if;
  1802.    end Destroy;
  1803.    ----------------------------------------------------------------------------------------------------------------------------
  1804.    procedure Destroy (Targeted_Object : in out Pointer_To_B_Plus_Tree) is
  1805.  
  1806.       procedure Annihilate is new Unchecked_Deallocation (B_Plus_Tree, Pointer_To_B_Plus_Tree);
  1807.  
  1808.    begin   -- procedure Destroy
  1809.       if (Targeted_Object /= null) then
  1810.          Destroy (Targeted_Object.all);
  1811.          Annihilate (Targeted_Object);
  1812.       end if;
  1813.    end Destroy;
  1814.    ----------------------------------------------------------------------------------------------------------------------------
  1815.    procedure Descend_And_Delete (Targeted_B_Plus_Tree   : in out B_Plus_Tree;
  1816.                                  Target_Node            : in out Internal_Node_Pointer;
  1817.                                  Minimum_Key_In_Subtree : in out Key_Pointer;
  1818.                                  Deletion_Type          : in     Type_Of_Deletion;
  1819.                                  Target_Key             : in     Key_Type;
  1820.                                  Target_Non_Key_Object  : in     Non_Key_Item_Type) is
  1821.  
  1822.  
  1823.       Path_Of_Descent   : Subtrees;
  1824.  
  1825.  
  1826.       procedure Delete_From_Leaf (Target_Leaf           : in out Internal_Node_Pointer;
  1827.                                   Deletion_Type         : in     Type_Of_Deletion;
  1828.                                   Target_Key            : in     Key_Type;
  1829.                                   Target_Non_Key_Object : in     Non_Key_Item_Type) is
  1830.  
  1831.          procedure Delete_Leaf (Targeted_B_Plus_Tree : in out B_Plus_Tree;
  1832.                                 Target_Leaf          : in out Internal_Node_Pointer) is
  1833.  
  1834.          begin   -- procedure Delete_Leaf
  1835.             if (Targeted_B_Plus_Tree.Current_Leaf = Target_Leaf) then
  1836.                Targeted_B_Plus_Tree.Current_Leaf := null;
  1837.             end if;
  1838.             if (Targeted_B_Plus_Tree.Minimum_Key = Target_Leaf.Key_Value) then
  1839.                if (Target_Leaf.Following_Leaf /= null) then
  1840.                   Targeted_B_Plus_Tree.Minimum_Key := Target_Leaf.Following_Leaf.Key_Value;
  1841.                else
  1842.                   Targeted_B_Plus_Tree.Minimum_Key := null;
  1843.                end if;
  1844.             end if;
  1845.             Destroy_Subtree (Target_Leaf);
  1846.             Targeted_B_Plus_Tree.Number_Of_Keys_Stored := Targeted_B_Plus_Tree.Number_Of_Keys_Stored - 1;
  1847.          end Delete_Leaf;
  1848.  
  1849.       begin   -- procedure Delete_From_Leaf
  1850.          if not Equal (Target_Leaf.Key_Value.all, Target_Key) then
  1851.             raise Key_Does_Not_Exist_In_This_B_Plus_Tree;
  1852.          elsif (Deletion_Type = Non_Key_Object) then
  1853.             Delete (Target_Leaf.Item_Container, Target_Non_Key_Object);
  1854.             if Empty (Target_Leaf.Item_Container) then
  1855.                Delete_Leaf (Targeted_B_Plus_Tree, Target_Leaf);
  1856.             end if;
  1857.          else   -- (Deletion_Type = Key) 
  1858.             Delete_Leaf (Targeted_B_Plus_Tree, Target_Leaf);
  1859.          end if;
  1860.       end Delete_From_Leaf;
  1861.  
  1862.  
  1863.       procedure Redistribute_Subtrees (Target_Node            : in out Internal_Node_Pointer;
  1864.                                        Minimum_Key_In_Subtree : in out Key_Pointer;
  1865.                                        Path_Of_Descent        : in     Subtrees               ) is
  1866.  
  1867.          Needy_Node                   : Internal_Node_Pointer;
  1868.          Minimum_Key_In_Needy_Node    : Key_Pointer;
  1869.          Left_Sibling                 : Internal_Node_Pointer := null;
  1870.          Minimum_Key_In_Left_Sibling  : Key_Pointer           := null;
  1871.          Right_Sibling                : Internal_Node_Pointer := null;
  1872.          Minimum_Key_In_Right_Sibling : Key_Pointer           := null;
  1873.          Extras_In_Left_Sibling       : Boolean;
  1874.          Extras_In_Right_Sibling      : Boolean;
  1875.  
  1876.       begin   -- procedure Redistribute_Subtrees
  1877.  
  1878.          Needy_Node := Target_Node.Subtree (Path_Of_Descent);
  1879.  
  1880.          if (Path_Of_Descent = 0) then
  1881.             Minimum_Key_In_Needy_Node := Minimum_Key_In_Subtree;
  1882.          else
  1883.             Minimum_Key_In_Needy_Node := Target_Node.Key ( Keys'Val ( Subtrees'Pos (Path_Of_Descent) ) );
  1884.          end if;
  1885.  
  1886.          case Path_Of_Descent is
  1887.  
  1888.             when 0 => Right_Sibling                := Target_Node.Subtree (1);
  1889.                       Minimum_Key_In_Right_Sibling := Target_Node.Key (1);
  1890.  
  1891.             when 1 => Left_Sibling                 := Target_Node.Subtree (0);
  1892.                       Minimum_Key_In_Left_Sibling  := Minimum_Key_In_Subtree;
  1893.                       Right_Sibling                := Target_Node.Subtree (2);
  1894.                       Minimum_Key_In_Right_Sibling := Target_Node.Key (2);
  1895.  
  1896.             when 2..(Maximum_Subtree_Number - 1) 
  1897.                    => Left_Sibling                 := Target_Node.Subtree (Path_Of_Descent - 1);
  1898.                       Minimum_Key_In_Left_Sibling  := Target_Node.Key (Keys'Val(Subtrees'Pos(Path_Of_Descent - 1)));
  1899.                       Right_Sibling                := Target_Node.Subtree (Path_Of_Descent + 1);
  1900.                       Minimum_Key_In_Right_Sibling := Target_Node.Key (Keys'Val(Subtrees'Pos(Path_Of_Descent + 1)));
  1901.  
  1902.             when Maximum_Subtree_Number
  1903.                    => Left_Sibling                 := Target_Node.Subtree (Maximum_Subtree_Number - 1);
  1904.                       Minimum_Key_In_Left_Sibling  := Target_Node.Key (Maximum_Subtree_Number - 1); 
  1905.  
  1906.          end case;
  1907.  
  1908.          Extras_In_Left_Sibling := ( (Left_Sibling /= null) 
  1909.                                         and then (Left_Sibling.Index_Node = True)
  1910.                                            and then (Left_Sibling.Maximum_Subtree_Index > Minimum_Subtree_Number));
  1911.  
  1912.          Extras_In_Right_Sibling := ( (Right_Sibling /= null) 
  1913.                                         and then (Right_Sibling.Index_Node = True)
  1914.                                            and then (Right_Sibling.Maximum_Subtree_Index > Minimum_Subtree_Number));
  1915.  
  1916.          if Extras_In_Left_Sibling and not Extras_In_Right_Sibling then
  1917.  
  1918.             Insert_Extra_Subtree (Needy_Node, Minimum_Key_In_Needy_Node,
  1919.                                      Left_Sibling.Subtree (Left_Sibling.Maximum_Subtree_Index),
  1920.                                         Left_Sibling.Key (Keys'Val(Subtrees'Pos(Left_Sibling.Maximum_Subtree_Index))));
  1921.             Delete_Subtree (Left_Sibling, Minimum_Key_In_Left_Sibling, Left_Sibling.Maximum_Subtree_Index);
  1922.             Target_Node.Key ( Keys'Val ( Subtrees'Pos (Path_Of_Descent) ) ) := Minimum_Key_In_Needy_Node;
  1923.  
  1924.          elsif Extras_In_Right_Sibling then
  1925.  
  1926.             Insert_Extra_Subtree (Needy_Node, Minimum_Key_In_Needy_Node, Right_Sibling.Subtree(0), Minimum_Key_In_Right_Sibling);
  1927.             Delete_Subtree (Right_Sibling, Minimum_Key_In_Right_Sibling, 0);
  1928.             Target_Node.Key ( Keys'Val ( Subtrees'Pos (Path_Of_Descent + 1) ) ) := Minimum_Key_In_Right_Sibling;
  1929.  
  1930.          elsif (Right_Sibling = null) or else (Left_Sibling /= null) then
  1931.  
  1932.             Insert_Extra_Subtree (Left_Sibling, Minimum_Key_In_Left_Sibling, Needy_Node.Subtree (0), Minimum_Key_In_Needy_Node);
  1933.             for Subtree_Number in 1..Needy_Node.Maximum_Subtree_Index loop
  1934.                Insert_Extra_Subtree (Left_Sibling, Minimum_Key_In_Left_Sibling, Needy_Node.Subtree (Subtree_Number), 
  1935.                                                               Needy_Node.Key ( Keys'Val ( Subtrees'Pos ( Subtree_Number ) ) ) );
  1936.             end loop;
  1937.             Destroy (Needy_Node);
  1938.             Delete_Subtree (Target_Node, Minimum_Key_In_Subtree, Path_Of_Descent);
  1939.  
  1940.          else  
  1941.  
  1942.             Insert_Extra_Subtree (Needy_Node, Minimum_Key_In_Needy_Node, Right_Sibling.Subtree (0), Minimum_Key_In_Right_Sibling);
  1943.             for Subtree_Number in 1..Right_Sibling.Maximum_Subtree_Index loop
  1944.                Insert_Extra_Subtree (Needy_Node, Minimum_Key_In_Needy_Node, Right_Sibling.Subtree (Subtree_Number),
  1945.                                                              Right_Sibling.Key ( Keys'Val ( Subtrees'Pos ( Subtree_Number))));
  1946.             end loop;
  1947.             Destroy (Right_Sibling);
  1948.             Delete_Subtree (Target_Node, Minimum_Key_In_Subtree, Path_Of_Descent + 1);
  1949.  
  1950.          end if;
  1951.  
  1952.       end Redistribute_Subtrees;
  1953.  
  1954.  
  1955.    begin   -- procedure Descend_And_Delete
  1956.  
  1957.       if (Target_Node.Index_Node = False) then 
  1958.  
  1959.          Delete_From_Leaf (Target_Node, Deletion_Type, Target_Key, Target_Non_Key_Object);
  1960.  
  1961.       else
  1962.  
  1963.          Path_Of_Descent := Determine_Path_Of_Descent (Target_Node, Target_Key);
  1964.  
  1965.          if (Path_Of_Descent = 0) then
  1966.             Descend_And_Delete ( Targeted_B_Plus_Tree, Target_Node.Subtree (0), 
  1967.                                     Minimum_Key_In_Subtree, Deletion_Type, Target_Key, Target_Non_Key_Object );
  1968.          else
  1969.             Descend_And_Delete ( Targeted_B_Plus_Tree, Target_Node.Subtree (Path_Of_Descent), 
  1970.                                    Target_Node.Key ( Keys'Val ( Subtrees'Pos (Path_Of_Descent) ) ),
  1971.                                       Deletion_Type, Target_Key, Target_Non_Key_Object                    );
  1972.          end if;
  1973.  
  1974.          if (Target_Node.Subtree (Path_Of_Descent) = null) then
  1975.             Delete_Subtree (Target_Node, Minimum_Key_In_Subtree, Path_Of_Descent);
  1976.          elsif (Target_Node.Subtree (Path_Of_Descent).Index_Node = True) 
  1977.            and then (Target_Node.Subtree (Path_Of_Descent).Maximum_Subtree_Index < Minimum_Subtree_Number) then
  1978.             Redistribute_Subtrees (Target_Node, Minimum_Key_In_Subtree, Path_Of_Descent);
  1979.          end if;
  1980.  
  1981.       end if;
  1982.    end Descend_And_Delete;
  1983.    ----------------------------------------------------------------------------------------------------------------------------
  1984.    procedure Delete_Key (Targeted_B_Plus_Tree : in out B_Plus_Tree;
  1985.                          Search_Key           : in     Key_Type    ) is
  1986.  
  1987.       -- Raises Key_Does_Not_Exist_In_This_B_Plus_Tree 
  1988.       --   or No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree, when appropriate...
  1989.       --
  1990.       -- The Non_Key_Item_Container associated with this key will be emptied via the Destroy_Contents procedure.
  1991.  
  1992.       Null_Non_Key_Information : Non_Key_Item_Type;
  1993.  
  1994.    begin   -- procedure Delete_Key
  1995.       if Empty (Targeted_B_Plus_Tree) then
  1996.          raise No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree;
  1997.       else
  1998.          Descend_And_Delete (Targeted_B_Plus_Tree, Targeted_B_Plus_Tree.Root_Node, 
  1999.                                Targeted_B_Plus_Tree.Minimum_Key, Key, Search_Key, Null_Non_Key_Information);
  2000.       end if;
  2001.    end Delete_Key;
  2002.    ----------------------------------------------------------------------------------------------------------------------------
  2003.    procedure Delete_Item (Targeted_B_Plus_Tree : in out B_Plus_Tree;
  2004.                           Key_Value            : in     Key_Type;
  2005.                           Non_Key_Information  : in     Non_Key_Item_Type) is
  2006.  
  2007.       -- Raises Key_Does_Not_Exist_In_This_B_Plus_Tree 
  2008.       --   or No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree, when appropriate...
  2009.  
  2010.    begin   -- procedure Delete_Item
  2011.       if Empty (Targeted_B_Plus_Tree) then
  2012.          raise No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree;
  2013.       else
  2014.          Descend_And_Delete (Targeted_B_Plus_Tree, Targeted_B_Plus_Tree.Root_Node, 
  2015.                                 Targeted_B_Plus_Tree.Minimum_Key, Non_Key_Object, Key_Value, Non_Key_Information);
  2016.          Targeted_B_Plus_Tree.Current_Leaf := null;
  2017.          if (Targeted_B_Plus_Tree.Root_Node.Maximum_Subtree_Index = 0) then
  2018.             if (Targeted_B_Plus_Tree.Root_Node.Subtree(0) /= null) then
  2019.                if (Targeted_B_Plus_Tree.Root_Node.Subtree(0).Index_Node = True) then
  2020.                   declare
  2021.                      Temp_Root : Internal_Node_Pointer := Targeted_B_Plus_Tree.Root_Node.Subtree(0);
  2022.                   begin
  2023.                      Destroy (Targeted_B_Plus_Tree.Root_Node);
  2024.                      Targeted_B_Plus_Tree.Root_Node := Temp_Root;
  2025.                   end;
  2026.                end if;
  2027.             else
  2028.                Destroy (Targeted_B_Plus_Tree.Root_Node);
  2029.                Destroy (Targeted_B_Plus_Tree);
  2030.             end if;
  2031.          end if;
  2032.       end if;
  2033.    end Delete_Item;
  2034.    ----------------------------------------------------------------------------------------------------------------------------
  2035.    function Get_First_Key (Targeted_B_Plus_Tree : in B_Plus_Tree) return Key_Type is
  2036.  
  2037.       -- Raises No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree when appropriate...
  2038.  
  2039.    begin   -- function Get_First_Key
  2040.       if Empty (Targeted_B_Plus_Tree) then
  2041.          raise No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree;
  2042.       else
  2043.          return Targeted_B_Plus_Tree.Minimum_Key.all;
  2044.       end if;
  2045.    end Get_First_Key;
  2046.    ----------------------------------------------------------------------------------------------------------------------------
  2047.    function Get_Last_Key (Targeted_B_Plus_Tree : in B_Plus_Tree) return Key_Type is
  2048.  
  2049.       -- Raises No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree when appropriate...
  2050.  
  2051.       function Return_Last_Key (This_Subtree : Internal_Node_Pointer) return Key_Type is
  2052.  
  2053.       begin   -- function Return_Last_Key
  2054.          if (This_Subtree.Index_Node = True) then
  2055.             return Return_Last_Key (This_Subtree.Subtree(This_Subtree.Maximum_Subtree_Index));
  2056.          else
  2057.             return This_Subtree.Key_Value.all;
  2058.          end if;
  2059.       end Return_Last_Key;
  2060.  
  2061.    begin   -- function Get_Last_Key
  2062.       if Empty (Targeted_B_Plus_Tree) then
  2063.          raise No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree;
  2064.       else
  2065.          return Return_Last_Key (Targeted_B_Plus_Tree.Root_Node);
  2066.       end if;
  2067.    end Get_Last_Key;
  2068.    ----------------------------------------------------------------------------------------------------------------------------
  2069.    function Get_Leaf_Node (This_B_Plus_Tree : in B_Plus_Tree;
  2070.                            Key_Value        : in Key_Type            ) return Internal_Node_Pointer is
  2071.  
  2072.       function Find_Leaf_Node (This_Subtree : in Internal_Node_Pointer;
  2073.                                Key_Value    : in Key_Type               ) return Internal_Node_Pointer is
  2074.  
  2075.          Path_Number : Subtrees := 0;
  2076.  
  2077.       begin   -- function Find_Leaf_Node
  2078.          if (This_Subtree.Index_Node = True) then
  2079.             while (Path_Number < This_Subtree.Maximum_Subtree_Index)
  2080.               and then not Less_Than (Key_Value, This_Subtree.Key(Keys'Val(Subtrees'Pos(Path_Number) + 1)).all) loop
  2081.                Path_Number := Path_Number + 1;
  2082.             end loop;
  2083.             return Find_Leaf_Node (This_Subtree.Subtree(Path_Number), Key_Value);
  2084.          else
  2085.             if Equal (This_Subtree.Key_Value.all, Key_Value) then
  2086.                return This_Subtree;
  2087.             else
  2088.                return null;
  2089.             end if;
  2090.          end if;
  2091.       end Find_Leaf_Node;
  2092.  
  2093.    begin   -- function Get_Leaf_Node
  2094.       if not Empty (This_B_Plus_Tree) then
  2095.          if (This_B_Plus_Tree.Current_Leaf /= null)
  2096.            and then Equal (This_B_Plus_Tree.Current_Leaf.Key_Value.all, Key_Value) then
  2097.             return This_B_Plus_Tree.Current_Leaf;
  2098.          else
  2099.             return Find_Leaf_Node (This_B_Plus_Tree.Root_Node, Key_Value);
  2100.          end if;
  2101.       else
  2102.          return null;
  2103.       end if;
  2104.    end Get_Leaf_Node;
  2105.    ----------------------------------------------------------------------------------------------------------------------------
  2106.    function Key_Exists (Targeted_B_Plus_Tree : in B_Plus_Tree;
  2107.                         Search_Key           : in Key_Type    ) return Boolean is
  2108.  
  2109.    begin   -- function Key_Exists
  2110.       if not Empty (Targeted_B_Plus_Tree) then
  2111.          Targeted_B_Plus_Tree.Current_Leaf := Get_Leaf_Node (Targeted_B_Plus_Tree, Search_Key);
  2112.          return (Targeted_B_Plus_Tree.Current_Leaf /= null);
  2113.       else
  2114.          return False;
  2115.       end if;
  2116.    end Key_Exists;
  2117.    ----------------------------------------------------------------------------------------------------------------------------
  2118.    function Get_Item_Container (Targeted_B_Plus_Tree : in B_Plus_Tree;
  2119.                                 Search_Key           : in Key_Type    ) return Non_Key_Item_Container is
  2120.  
  2121.       -- Raises Key_Does_Not_Exist_In_This_B_Plus_Tree 
  2122.       --   or No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree, when appropriate...
  2123.  
  2124.    begin   -- function Get_Item_Container
  2125.       if Empty (Targeted_B_Plus_Tree) then
  2126.          raise No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree;
  2127.       else
  2128.          Targeted_B_Plus_Tree.Current_Leaf := Get_Leaf_Node (Targeted_B_Plus_Tree, Search_Key);
  2129.          if (Targeted_B_Plus_Tree.Current_Leaf = null) then
  2130.             raise Key_Does_Not_Exist_In_This_B_Plus_Tree;
  2131.          else
  2132.             return Targeted_B_Plus_Tree.Current_Leaf.Item_Container;
  2133.          end if;
  2134.       end if;
  2135.    end Get_Item_Container;
  2136.    ----------------------------------------------------------------------------------------------------------------------------
  2137.    function A_Preceding_Key_Exists (Targeted_B_Plus_Tree : in B_Plus_Tree;
  2138.                                     Search_Key           : in Key_Type     ) return Boolean is
  2139.  
  2140.    begin   -- function A_Preceding_Key_Exists
  2141.       Targeted_B_Plus_Tree.Current_Leaf := Get_Leaf_Node (Targeted_B_Plus_Tree, Search_Key);
  2142.       return ( not Empty (Targeted_B_Plus_Tree)
  2143.                  and then (Targeted_B_Plus_Tree.Current_Leaf /= null) 
  2144.                  and then (Targeted_B_Plus_Tree.Current_Leaf.Preceding_Leaf /= null) );
  2145.    end A_Preceding_Key_Exists;
  2146.    ----------------------------------------------------------------------------------------------------------------------------
  2147.    function Get_Preceding_Key (Targeted_B_Plus_Tree : in B_Plus_Tree;
  2148.                                Search_Key           : in Key_Type     ) return Key_Type is
  2149.  
  2150.       -- Raises Key_Does_Not_Exist_In_This_B_Plus_Tree 
  2151.       --   or No_Preceding_Key_Exists_In_This_B_Plus_Tree
  2152.       --   or No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree, when appropriate...
  2153.  
  2154.       Temp : Key_Type;
  2155.  
  2156.    begin   -- function Get_Preceding_Key
  2157.       if not Empty (Targeted_B_Plus_Tree) then
  2158.          Targeted_B_Plus_Tree.Current_Leaf := Get_Leaf_Node (Targeted_B_Plus_Tree, Search_Key);
  2159.          if (Targeted_B_Plus_Tree.Current_Leaf /= null) 
  2160.           and then (Targeted_B_Plus_Tree.Current_Leaf.Preceding_Leaf /= null) then
  2161.             return Targeted_B_Plus_Tree.Current_Leaf.Preceding_Leaf.Key_Value.all;
  2162.          elsif (Targeted_B_Plus_Tree.Current_Leaf.Preceding_Leaf = null) then
  2163.             raise No_Preceding_Key_Exists_In_This_B_Plus_Tree;
  2164.          elsif (Targeted_B_Plus_Tree.Current_Leaf = null) then
  2165.             raise Key_Does_Not_Exist_In_This_B_Plus_Tree;
  2166.          end if;
  2167.       else
  2168.          raise No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree;
  2169.       end if;  
  2170.    end Get_Preceding_Key;
  2171.    ----------------------------------------------------------------------------------------------------------------------------
  2172.    function A_Following_Key_Exists  (Targeted_B_Plus_Tree : in B_Plus_Tree;
  2173.                                      Search_Key           : in Key_Type     ) return Boolean is
  2174.  
  2175.    begin   -- function A_Following_Key_Exists
  2176.       Targeted_B_Plus_Tree.Current_Leaf := Get_Leaf_Node (Targeted_B_Plus_Tree, Search_Key);
  2177.       return ( not Empty (Targeted_B_Plus_Tree)
  2178.                  and then (Targeted_B_Plus_Tree.Current_Leaf /= null) 
  2179.                  and then (Targeted_B_Plus_Tree.Current_Leaf.Following_Leaf /= null) );
  2180.    end A_Following_Key_Exists;
  2181.    ----------------------------------------------------------------------------------------------------------------------------
  2182.    function Get_Following_Key  (Targeted_B_Plus_Tree : in B_Plus_Tree;
  2183.                                 Search_Key           : in Key_Type     ) return Key_Type is
  2184.  
  2185.       -- Raises Key_Does_Not_Exist_In_This_B_Plus_Tree 
  2186.       --   or No_Following_Key_Exists_In_This_B_Plus_Tree 
  2187.       --   or No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree, when appropriate...
  2188.  
  2189.    begin   -- function Get_Following_Key
  2190.       if not Empty (Targeted_B_Plus_Tree) then
  2191.          Targeted_B_Plus_Tree.Current_Leaf := Get_Leaf_Node (Targeted_B_Plus_Tree, Search_Key);
  2192.          if (Targeted_B_Plus_Tree.Current_Leaf /= null) 
  2193.           and then (Targeted_B_Plus_Tree.Current_Leaf.Following_Leaf /= null) then
  2194.             return Targeted_B_Plus_Tree.Current_Leaf.Following_Leaf.Key_Value.all;
  2195.          elsif (Targeted_B_Plus_Tree.Current_Leaf.Following_Leaf = null) then
  2196.             raise No_Following_Key_Exists_In_This_B_Plus_Tree;
  2197.          elsif (Targeted_B_Plus_Tree.Current_Leaf = null) then
  2198.             raise Key_Does_Not_Exist_In_This_B_Plus_Tree;
  2199.          end if;
  2200.       else
  2201.          raise No_Keys_Currently_Exist_In_This_Empty_B_Plus_Tree;
  2202.       end if;  
  2203.    end Get_Following_Key;
  2204.    ----------------------------------------------------------------------------------------------------------------------------
  2205.    procedure Assign (To_B_Plus_Tree   : in out B_Plus_Tree;
  2206.                      From_B_Plus_Tree : in     B_Plus_Tree) is
  2207.  
  2208.       Last_Leaf : Internal_Node_Pointer;
  2209.  
  2210.       procedure Assign (To_Internal_Node       : in out Internal_Node_Pointer;
  2211.                         Minimum_Key_In_Subtree :    out Key_Pointer;
  2212.                         From_Internal_Node     : in     Internal_Node_Pointer) is
  2213.  
  2214.       begin   -- procedure Assign
  2215.          To_Internal_Node := new Internal_Node (Index_Node => From_Internal_Node.Index_Node);
  2216.          if From_Internal_Node.Index_Node then
  2217.             To_Internal_Node.Maximum_Subtree_Index := From_Internal_Node.Maximum_Subtree_Index;
  2218.             Assign (To_Internal_Node.Subtree (0), Minimum_Key_In_Subtree, From_Internal_Node.Subtree (0));
  2219.             for Subtree_Number in 1..From_Internal_Node.Maximum_Subtree_Index loop
  2220.                Assign (To_Internal_Node.Subtree (Subtree_Number),
  2221.                           To_Internal_Node.Key ( Keys'Val ( Subtrees'Pos (Subtree_Number) ) ),
  2222.                              From_Internal_Node.Subtree (Subtree_Number));
  2223.             end loop;
  2224.          else
  2225.             To_Internal_Node.Preceding_Leaf := Last_Leaf;
  2226.             Last_Leaf.Following_Leaf := To_Internal_Node;
  2227.             To_Internal_Node.Key_Value := new Key_Type;
  2228.             Assign (To_Internal_Node.Key_Value.all, From_Internal_Node.Key_Value.all);
  2229.             Assign (To_Internal_Node.Item_Container, From_Internal_Node.Item_Container);
  2230.             Last_Leaf := To_Internal_Node;
  2231.          end if;
  2232.       end Assign;
  2233.  
  2234.    begin   -- procedure Assign
  2235.       Destroy (To_B_Plus_Tree);
  2236.       if (From_B_Plus_Tree /= null) then
  2237.          To_B_Plus_Tree := new B_Plus_Tree_Descriptor;
  2238.          Assign (To_B_Plus_Tree.Root_Node, To_B_Plus_Tree.Minimum_Key, From_B_Plus_Tree.Root_Node);
  2239.          To_B_Plus_Tree.Current_Leaf := Get_Leaf_Node (To_B_Plus_Tree, From_B_Plus_Tree.Current_Leaf.Key_Value.all);
  2240.          To_B_Plus_Tree.Number_Of_Keys_Stored := From_B_Plus_Tree.Number_Of_Keys_Stored;
  2241.       end if;
  2242.    end Assign;
  2243.    ----------------------------------------------------------------------------------------------------------------------------
  2244.  
  2245.  
  2246. end BP_Tree;
  2247. --::::::::::
  2248. --cisc.bdy
  2249. --::::::::::
  2250. package body case_insensitive_string_comparison is
  2251.  
  2252. --| Overview
  2253. --| Strings are compared one character at a time, stopping as soon as
  2254. --| possible. 
  2255.  
  2256. --| Programmer: M. Gordon
  2257.  
  2258. ------------------------------------------------------------------------
  2259.  
  2260. Up_ConvertArray: array(Character) of Character;
  2261. Down_ConvertArray: array(Character) of Character;
  2262. Difference: constant := Character'pos('a') - Character'pos('A');
  2263.  
  2264. function toUpper(C: character) return character is
  2265. begin
  2266.     return Up_ConvertArray(C);
  2267.  
  2268. end toUpper;
  2269.  
  2270.  
  2271. function upCase(    --| Return copy of S with all characters lower case
  2272.     S: String
  2273.     ) return String
  2274. is
  2275.     R: String(S'Range) := S;
  2276.  
  2277. begin
  2278.     for i in R'Range loop
  2279.     R(i) := toUpper(R(i));
  2280.     end loop;
  2281.     return R;
  2282.  
  2283. end upCase;
  2284.  
  2285.  
  2286. procedure upCase(    --| Convert all characters in S to lower case
  2287.     S: in out String
  2288.     ) is
  2289.  
  2290. begin
  2291.     for i in S'Range loop
  2292.     S(i) := toUpper(S(i));
  2293.     end loop;
  2294.  
  2295. end upCase;
  2296.  
  2297. ------------------------------------------------------------------------
  2298.  
  2299. function toLower(C: character) return character is
  2300. begin
  2301.     return Down_ConvertArray(C);
  2302.  
  2303. end toLower;
  2304.  
  2305.  
  2306. function downCase(    --| Return copy of S with all characters lower case
  2307.     S: String
  2308.     ) return String
  2309. is
  2310.     R: String(S'Range) := S;
  2311.  
  2312. begin
  2313.     for i in R'Range loop
  2314.     R(i) := toLower(R(i));
  2315.     end loop;
  2316.     return R;
  2317.  
  2318. end downCase;
  2319.  
  2320. procedure downCase(    --| Convert all characters in S to lower case
  2321.     S: in out String
  2322.     ) is
  2323.  
  2324. begin
  2325.     for i in S'Range loop
  2326.     S(i) := toLower(S(i));
  2327.     end loop;
  2328.  
  2329. end downCase;
  2330.  
  2331. ------------------------------------------------------------------------
  2332.  
  2333. function compare(    --| Compare two strings
  2334.     P, Q: String
  2335.     ) return integer
  2336. is
  2337.     QI: natural;
  2338.     PC, QC: character;
  2339.  
  2340. begin
  2341.     QI := Q'First;
  2342.     for PI in P'First .. P'Last loop
  2343.       if QI > Q'Last then
  2344.     return 1;    -- Q ran out before P did.
  2345.       end if;
  2346.       PC := toUpper(P(PI));
  2347.       QC := toUpper(Q(QI));
  2348.       if PC /= QC then
  2349.     return character'pos(PC) - character'pos(QC);
  2350.       end if;
  2351.       QI := QI + 1;
  2352.     end loop;
  2353.     return P'Length - Q'Length;    -- Equal so far: longer string is greater
  2354.  
  2355. end compare;
  2356.  
  2357. ------------------------------------------------------------------------
  2358.  
  2359. function equal(
  2360.     P, Q: String
  2361.     ) return boolean is
  2362. begin
  2363.     return compare(P, Q) = 0;
  2364.  
  2365. end equal;
  2366.  
  2367. ------------------------------------------------------------------------
  2368.  
  2369. function less(
  2370.     P, Q: String
  2371.     ) return boolean is
  2372. begin
  2373.     return compare(P, Q) < 0;
  2374. end less;
  2375.  
  2376.  
  2377. function less_or_equal(
  2378.     P, Q: String
  2379.     ) return boolean is
  2380. begin
  2381.     return compare(P, Q) <= 0;
  2382. end less_or_equal;
  2383.  
  2384.  
  2385. ------------------------------------------------------------------------
  2386.  
  2387. function greater(
  2388.     P, Q: String
  2389.     ) return boolean is
  2390. begin
  2391.     return compare(P, Q) > 0;
  2392. end greater;
  2393.  
  2394. function greater_or_equal(
  2395.     P, Q: String
  2396.     ) return boolean is
  2397. begin
  2398.     return compare(P, Q) >= 0;
  2399. end greater_or_equal;
  2400.  
  2401. ------------------------------------------------------------------------
  2402.  
  2403. begin
  2404.  
  2405.   for I in Character loop
  2406.     case I is
  2407.       when 'a' .. 'z' => 
  2408.         Up_ConvertArray(I) := Character'val(Character'pos(I) - Difference);
  2409.       when others =>
  2410.         Up_ConvertArray(I) := I;
  2411.     end case;
  2412.   end loop;
  2413.  
  2414.   for I in Character loop
  2415.     case I is
  2416.       when 'A' .. 'Z' => 
  2417.         Down_ConvertArray(I) := Character'val(Character'pos(I) + Difference);
  2418.       when others =>
  2419.         Down_ConvertArray(I) := I;
  2420.     end case;
  2421.   end loop;
  2422.  
  2423. end case_insensitive_string_comparison;
  2424. --::::::::::
  2425. --cset.bdy
  2426. --::::::::::
  2427. package body CHARACTER_SET is
  2428.  
  2429.    function  TO_LOWER (CH : in CHARACTER) return CHARACTER is
  2430.    begin
  2431.       return LOWER (CH);
  2432.    end TO_LOWER;
  2433.  
  2434.    procedure TO_LOWER (CH : in out CHARACTER) is
  2435.    begin
  2436.       CH := LOWER (CH);
  2437.    end TO_LOWER;
  2438.  
  2439.    procedure TO_LOWER (STR : in out STRING) is
  2440.    begin
  2441.       for I in STR'FIRST .. STR'LAST loop
  2442.          STR (I) := LOWER (STR (I));
  2443.       end loop;
  2444.    end TO_LOWER;
  2445.  
  2446.    function  TO_UPPER (CH : in CHARACTER) return CHARACTER is
  2447.    begin
  2448.       return UPPER (CH);
  2449.    end TO_UPPER;
  2450.  
  2451.    procedure TO_UPPER (CH : in out CHARACTER) is
  2452.    begin
  2453.       CH := UPPER (CH);
  2454.    end TO_UPPER;
  2455.  
  2456.    procedure TO_UPPER (STR : in out STRING) is
  2457.    begin
  2458.       for I in STR'FIRST .. STR'LAST loop
  2459.          STR (I) := UPPER (STR (I));
  2460.       end loop;
  2461.    end TO_UPPER;
  2462.  
  2463.    function  CC_NAME_2 (CH : CHARACTER) return CONTROL_CHARACTER_NAME_2 is
  2464.       NAME : CONTROL_CHARACTER_NAME_2;
  2465.    begin
  2466.       case CH is
  2467.          when ASCII.NUL => NAME := "^@";
  2468.          when ASCII.SOH => NAME := "^A";
  2469.          when ASCII.STX => NAME := "^B";
  2470.          when ASCII.ETX => NAME := "^C";
  2471.          when ASCII.EOT => NAME := "^D";
  2472.          when ASCII.ENQ => NAME := "^E";
  2473.          when ASCII.ACK => NAME := "^F";
  2474.          when ASCII.BEL => NAME := "^G";
  2475.          when ASCII.BS  => NAME := "^H";
  2476.          when ASCII.HT  => NAME := "^I";
  2477.          when ASCII.LF  => NAME := "^J";
  2478.          when ASCII.VT  => NAME := "^K";
  2479.          when ASCII.FF  => NAME := "^L";
  2480.          when ASCII.CR  => NAME := "^M";
  2481.          when ASCII.SO  => NAME := "^N";
  2482.          when ASCII.SI  => NAME := "^O";
  2483.          when ASCII.DLE => NAME := "^P";
  2484.          when ASCII.DC1 => NAME := "^Q";
  2485.          when ASCII.DC2 => NAME := "^R";
  2486.          when ASCII.DC3 => NAME := "^S";
  2487.          when ASCII.DC4 => NAME := "^T";
  2488.          when ASCII.NAK => NAME := "^U";
  2489.          when ASCII.SYN => NAME := "^V";
  2490.          when ASCII.ETB => NAME := "^W";
  2491.          when ASCII.CAN => NAME := "^X";
  2492.          when ASCII.EM  => NAME := "^Y";
  2493.          when ASCII.SUB => NAME := "^Z";
  2494.          when ASCII.ESC => NAME := "^[";
  2495.          when ASCII.FS  => NAME := "^\";
  2496.          when ASCII.GS  => NAME := "^]";
  2497.          when ASCII.RS  => NAME := "^^";
  2498.          when ASCII.US  => NAME := "^_";
  2499.          when ASCII.DEL => NAME := "^`";
  2500.          when others =>
  2501.             NAME := "  ";
  2502.             NAME (2) := CH;
  2503.       end case;
  2504.       return NAME;
  2505.    end CC_NAME_2;
  2506.  
  2507.    function  CC_NAME_3 (CH : CHARACTER) return CONTROL_CHARACTER_NAME_3 is
  2508.       NAME : CONTROL_CHARACTER_NAME_3;
  2509.    begin
  2510.       case CH is
  2511.          when ASCII.NUL => NAME := "NUL";
  2512.          when ASCII.SOH => NAME := "SOH";
  2513.          when ASCII.STX => NAME := "STX";
  2514.          when ASCII.ETX => NAME := "ETX";
  2515.          when ASCII.EOT => NAME := "EOT";
  2516.          when ASCII.ENQ => NAME := "ENQ";
  2517.          when ASCII.ACK => NAME := "ACK";
  2518.          when ASCII.BEL => NAME := "BEL";
  2519.          when ASCII.BS  => NAME := "BS ";
  2520.          when ASCII.HT  => NAME := "HT ";
  2521.          when ASCII.LF  => NAME := "LF ";
  2522.          when ASCII.VT  => NAME := "VT ";
  2523.          when ASCII.FF  => NAME := "FF ";
  2524.          when ASCII.CR  => NAME := "CR ";
  2525.          when ASCII.SO  => NAME := "SO ";
  2526.          when ASCII.SI  => NAME := "SI ";
  2527.          when ASCII.DLE => NAME := "DLE";
  2528.          when ASCII.DC1 => NAME := "DC1";
  2529.          when ASCII.DC2 => NAME := "DC2";
  2530.          when ASCII.DC3 => NAME := "DC3";
  2531.          when ASCII.DC4 => NAME := "DC4";
  2532.          when ASCII.NAK => NAME := "NAK";
  2533.          when ASCII.SYN => NAME := "SYN";
  2534.          when ASCII.ETB => NAME := "ETB";
  2535.          when ASCII.CAN => NAME := "CAN";
  2536.          when ASCII.EM  => NAME := "EM ";
  2537.          when ASCII.SUB => NAME := "SUB";
  2538.          when ASCII.ESC => NAME := "ESC";
  2539.          when ASCII.FS  => NAME := "FS ";
  2540.          when ASCII.GS  => NAME := "GS ";
  2541.          when ASCII.RS  => NAME := "RS ";
  2542.          when ASCII.US  => NAME := "US ";
  2543.          when ASCII.DEL => NAME := "DEL";
  2544.          when others =>
  2545.             NAME := "   ";
  2546.             NAME (2) := CH;
  2547.       end case;
  2548.       return NAME;
  2549.    end CC_NAME_3;
  2550. end CHARACTER_SET;
  2551. --::::::::::
  2552. --cssc.bdy
  2553. --::::::::::
  2554. package body case_sensitive_string_comparison is
  2555.  
  2556. --| Overview
  2557. --| Strings are compared one character at a time, stopping as soon as
  2558. --| possible. 
  2559.  
  2560. --| Programmer: M. Gordon
  2561.  
  2562. ------------------------------------------------------------------------
  2563.  
  2564. function compare(    --| Compare two strings
  2565.     P, Q: String
  2566.     ) return integer
  2567. is
  2568.     QI: natural;
  2569.  
  2570. begin
  2571.     QI := Q'First;
  2572.     for PI in P'First .. P'Last loop
  2573.       if QI > Q'Last then
  2574.     return 1;    -- Q ran out before P did.
  2575.       end if;
  2576.       if P(PI) /= Q(QI) then
  2577.     return character'pos(P(PI)) - character'pos(Q(QI));
  2578.       end if;
  2579.       QI := QI + 1;
  2580.     end loop;
  2581.     return P'Length - Q'Length;    -- Equal so far: longer string is greater
  2582.  
  2583. end  compare;
  2584.  
  2585. ------------------------------------------------------------------------
  2586.  
  2587. function equal(
  2588.     P, Q: String
  2589.     ) return boolean is
  2590. begin
  2591.     return P = Q;
  2592.  
  2593. end equal;
  2594.  
  2595. ------------------------------------------------------------------------
  2596.  
  2597. function less(
  2598.     P, Q: String
  2599.     ) return boolean is
  2600. begin
  2601.     return P < Q;
  2602. end less;
  2603.  
  2604.  
  2605. function less_or_equal(
  2606.     P, Q: String
  2607.     ) return boolean is
  2608. begin
  2609.     return P <= Q;
  2610. end less_or_equal;
  2611.  
  2612.  
  2613. ------------------------------------------------------------------------
  2614.  
  2615. function greater(
  2616.     P, Q: String
  2617.     ) return boolean is
  2618. begin
  2619.     return P > Q;
  2620. end greater;
  2621.  
  2622. function greater_or_equal(
  2623.     P, Q: String
  2624.     ) return boolean is
  2625. begin
  2626.     return P >= Q;
  2627. end greater_or_equal;
  2628.  
  2629. ------------------------------------------------------------------------
  2630.  
  2631. end case_sensitive_string_comparison;
  2632. --::::::::::
  2633. --cstrings.bdy
  2634. --::::::::::
  2635. -- ********************************************************
  2636. -- *                                                      *
  2637. -- *  CStrings                                            *  BODY
  2638. -- *                                                      *
  2639. -- ********************************************************
  2640. package body CStrings is
  2641. --| Notes
  2642. --|   Reference Sun Release 4.0 man pages on "strings".
  2643.  
  2644.   Work  : STRING(1..Max_String_Length);
  2645.   Work2 : STRING(1..Max_String_Length);
  2646.   Work3 : STRING(1..Max_String_Length);
  2647.  
  2648.   Charpos_LC_A : constant := CHARACTER'POS('a');
  2649.   Charpos_UC_A : constant := CHARACTER'POS('A');
  2650.  
  2651.   -- ...................................................
  2652.   -- .                                                 .
  2653.   -- .  CStrings.Toupper                               .  SPEC & BODY
  2654.   -- .                                                 .
  2655.   -- ...................................................
  2656.   function Toupper (Item : in CHARACTER) return CHARACTER is
  2657.     Result : CHARACTER := Item;
  2658.   begin
  2659.     if Item in 'a' .. 'z' then
  2660.       Result := CHARACTER'VAL(CHARACTER'POS(Item) - Charpos_LC_A +
  2661.                               Charpos_UC_A);
  2662.     end if;
  2663.     return Result;
  2664.   end Toupper;
  2665.   pragma inline (Toupper);
  2666.  
  2667.   -- ...................................................
  2668.   -- .                                                 .
  2669.   -- .  CStrings.Char_is_in_String                     .  SPEC & BODY
  2670.   -- .                                                 .
  2671.   -- ...................................................
  2672.   function Char_is_in_String (Ch : in CHARACTER;
  2673.                               S  : in STRING) return BOOLEAN is
  2674.   begin
  2675.     return Strchr(S, Ch) /= 0;
  2676.   end Char_is_in_String;
  2677.   pragma inline (Char_is_in_String);
  2678.  
  2679.   -- ...................................................
  2680.   -- .                                                 .
  2681.   -- .  CStrings.Copy                                  .  SPEC & BODY
  2682.   -- .                                                 .
  2683.   -- ...................................................
  2684.   procedure Copy (Source      : in STRING;
  2685.                   Destination : out STRING;
  2686.                   D_Start     : in NATURAL) is
  2687.   --| Note
  2688.   --|   Any exception raised here (probably CONSTRAINT_ERROR)
  2689.   --| is to be handled by the caller.
  2690.     S : NATURAL;
  2691.   begin
  2692.     S := Strlen(Source);
  2693.     if S > 0 then
  2694.       Destination(D_Start..D_Start+S-1)
  2695.         := Source(Source'FIRST .. Source'FIRST+S-1);
  2696.     end if;
  2697.     Destination(D_Start+S) := ASCII.NUL;
  2698.   end Copy;
  2699.   pragma inline (Copy);
  2700.  
  2701.   -- ...................................................
  2702.   -- .                                                 .
  2703.   -- .  CStrings.Make_Cstring                          .  BODY
  2704.   -- .                                                 .
  2705.   -- ...................................................
  2706.   procedure Make_Cstring (From : in STRING;
  2707.                           To   : out STRING) is
  2708.   begin
  2709.     To(To'FIRST .. To'FIRST + From'LENGTH - 1)
  2710.       := From;
  2711.     To(To'FIRST + From'LENGTH) := ASCII.NUL;
  2712.   exception
  2713.     when others => raise LENGTH_ERROR;
  2714.   end Make_Cstring;
  2715.  
  2716.   -- ...................................................
  2717.   -- .                                                 .
  2718.   -- .  CStrings.Make_Cstring                          .  BODY
  2719.   -- .                                                 .
  2720.   -- ...................................................
  2721.   procedure Make_Cstring (From_To : in out STRING;
  2722.                           Index   : in NATURAL) is
  2723.   begin
  2724.     From_To(Index) := ASCII.NUL;
  2725.   exception
  2726.     when others => raise LENGTH_ERROR;
  2727.   end Make_Cstring;
  2728.  
  2729.   -- ...................................................
  2730.   -- .                                                 .
  2731.   -- .  CStrings.Ada_String                            .  BODY
  2732.   -- .                                                 .
  2733.   -- ...................................................
  2734.   function Ada_String (From : in STRING) return STRING is
  2735.   begin
  2736.     return From(From'FIRST .. From'FIRST + Strlen(From) - 1);
  2737.   end Ada_String;
  2738.  
  2739.   -- ...................................................
  2740.   -- .                                                 .
  2741.   -- .  CStrings.Strcat                                .  BODY
  2742.   -- .                                                 .
  2743.   -- ...................................................
  2744.   procedure Strcat (To   : in out STRING;
  2745.                     From : in STRING) is
  2746.   begin
  2747.     Copy(To, Work, Work'FIRST);
  2748.     Copy(From, Work, Work'FIRST + Strlen(To));
  2749.     Copy(Work, To, To'FIRST);
  2750.   exception
  2751.     when others => raise LENGTH_ERROR;
  2752.   end Strcat;
  2753.  
  2754.   -- ...................................................
  2755.   -- .                                                 .
  2756.   -- .  CStrings.Strcat                                .  BODY
  2757.   -- .                                                 .
  2758.   -- ...................................................
  2759.   function Strcat (From_Part_1 : in STRING;
  2760.                    From_Part_2 : in STRING) return STRING is
  2761.   --| Note
  2762.   --|   Buffer Work2 is used because procedure Strcat uses
  2763.   --| buffer Work.
  2764.   begin
  2765.     Strcpy(From_Part_1, Work2);
  2766.     Strcat(Work2, From_Part_2);
  2767.     return Work2(Work2'FIRST .. Work2'FIRST + Strlen(Work2));
  2768.   exception
  2769.     when others => raise LENGTH_ERROR;
  2770.   end Strcat;
  2771.  
  2772.   -- ...................................................
  2773.   -- .                                                 .
  2774.   -- .  CStrings.Strncat                               .  BODY
  2775.   -- .                                                 .
  2776.   -- ...................................................
  2777.   procedure Strncat (To     : in out STRING;
  2778.                      From   : in STRING;
  2779.                      Length : in NATURAL) is
  2780.   --| Note
  2781.   --|   Buffer Work2 is used because procedure Strcat uses
  2782.   --| buffer Work.
  2783.   begin
  2784.     Copy(From, Work2, Work2'FIRST);
  2785.     Work2(Work2'FIRST + Length) := ASCII.NUL;
  2786.     Strcat(To, Work2);
  2787.   exception
  2788.     when others       => raise LENGTH_ERROR;
  2789.   end Strncat;
  2790.  
  2791.   -- ...................................................
  2792.   -- .                                                 .
  2793.   -- .  CStrings.Strncat                               .  BODY
  2794.   -- .                                                 .
  2795.   -- ...................................................
  2796.   function Strncat (To     : in STRING;
  2797.                     From   : in STRING;
  2798.                     Length : in NATURAL) return STRING is
  2799.   --| Note
  2800.   --|   Buffer Work3 is used because procedure Strcat uses
  2801.   --| buffer Work and procedure Strncat uses buffer Work2.
  2802.   begin
  2803.     Copy(To, Work3, Work3'FIRST);
  2804.     Strncat(Work3, From, Length);
  2805.     return Work3(Work3'FIRST .. Work3'FIRST + Strlen(Work3));
  2806.   exception
  2807.     when others       => raise LENGTH_ERROR;
  2808.   end Strncat;
  2809.  
  2810.   -- ...................................................
  2811.   -- .                                                 .
  2812.   -- .  CStrings.Strcmp                                .  BODY
  2813.   -- .                                                 .
  2814.   -- ...................................................
  2815.   function Strcmp (String1 : in STRING;
  2816.                    String2 : in STRING)
  2817.       return COMPARISON_RESULT is
  2818.     Result : COMPARISON_RESULT := EQUAL_TO;
  2819.     S1 : NATURAL := String1'FIRST;
  2820.     S2 : NATURAL := String2'FIRST;
  2821.     Loop_Exit : BOOLEAN;
  2822.   begin
  2823.     if String1'LENGTH > 0 and String2'LENGTH > 0 then
  2824.  
  2825.       -- Both strings are not empty (contain at least
  2826.       -- ASCII.NUL)
  2827.       while String1(S1) /= ASCII.NUL loop
  2828.  
  2829.         -- loop thru String1, comparing it char-for-char
  2830.         -- with String2
  2831.         Loop_Exit := FALSE;  -- indicates abnormal loop exit
  2832.         if String1(S1) /= String2(S2) then
  2833.  
  2834.           -- if the two chars are not the same,
  2835.           -- then we can determine a result
  2836.           if String1(S1) < String2(S2) then
  2837.             Result := LESS_THAN;
  2838.           else
  2839.             Result := GREATER_THAN;
  2840.           end if;
  2841.           exit;
  2842.         end if;
  2843.  
  2844.         -- the two strings are the same so far, so
  2845.         -- continue advancing thru them
  2846.         S1 := S1 + 1;
  2847.         S2 := S2 + 1;
  2848.  
  2849.         -- done if we are past the ends of both strings
  2850.         exit when S1 > String1'LAST and S2 > String2'LAST;
  2851.  
  2852.         -- we can determine the result if we are past the
  2853.         -- end of String1 but not String2
  2854.         if S1 > String1'LAST then
  2855.           if String2(S2) /= ASCII.NUL then
  2856.             Result := LESS_THAN;
  2857.           end if;
  2858.           exit;
  2859.         end if;
  2860.  
  2861.         -- we can determine the result if we are past the
  2862.         -- end of String2 but not String1
  2863.         if S2 > String2'LAST then
  2864.           if String1(S1) /= ASCII.NUL then
  2865.             Result := GREATER_THAN;
  2866.           end if;
  2867.           exit;
  2868.         end if;
  2869.         Loop_Exit := TRUE;  -- indicates normal exit of loop
  2870.       end loop;
  2871.  
  2872.       -- we have exited the loop either normally or abnormally
  2873.       -- (abnormally is via an exit statement); if normally,
  2874.       -- then we have reached the end of String1 and the result
  2875.       -- is EQUAL_TO unless we have also reached the end of
  2876.       -- String2
  2877.       if Loop_Exit then
  2878.         if String2(S2) /= ASCII.NUL then
  2879.           Result := LESS_THAN;
  2880.         end if;
  2881.       end if;
  2882.     else
  2883.  
  2884.       -- one of the strings is empty, so determine the
  2885.       -- result (Result is already EQUAL_TO, so if either
  2886.       -- string has some length, then Result changes)
  2887.       if String1'LENGTH > 0 then
  2888.         Result := GREATER_THAN;
  2889.       elsif String2'LENGTH > 0 then
  2890.         Result := LESS_THAN;
  2891.       end if;
  2892.     end if;
  2893.  
  2894.     -- Result is the answer
  2895.     return Result;
  2896.   end Strcmp;
  2897.  
  2898.   -- ...................................................
  2899.   -- .                                                 .
  2900.   -- .  CStrings.Strncmp                               .  BODY
  2901.   -- .                                                 .
  2902.   -- ...................................................
  2903.   function Strncmp (String1 : in STRING;
  2904.                     String2 : in STRING;
  2905.                     Length  : in NATURAL)
  2906.       return COMPARISON_RESULT is
  2907.     Result : COMPARISON_RESULT := EQUAL_TO;
  2908.     S1 : NATURAL := String1'FIRST;
  2909.     S2 : NATURAL := String2'FIRST;
  2910.     Count : NATURAL := Length;
  2911.     Loop_Exit : BOOLEAN;
  2912.   begin
  2913.     if (String1'LENGTH > 0 and String2'LENGTH > 0) and
  2914.        (Count > 0) then
  2915.  
  2916.       -- Both strings are not empty (contain at least
  2917.       -- ASCII.NUL) and Count is non-zero
  2918.       while String1(S1) /= ASCII.NUL loop
  2919.  
  2920.         -- loop thru String1, comparing it char-for-char
  2921.         -- with String2
  2922.         Loop_Exit := FALSE;  -- indicates abnormal loop exit
  2923.         if String1(S1) /= String2(S2) then
  2924.  
  2925.           -- if the two chars are not the same,
  2926.           -- then we can determine a result
  2927.           if String1(S1) < String2(S2) then
  2928.             Result := LESS_THAN;
  2929.           else
  2930.             Result := GREATER_THAN;
  2931.           end if;
  2932.           exit;
  2933.         end if;
  2934.  
  2935.         -- the two strings are the same so far, so
  2936.         -- continue advancing thru them
  2937.         S1 := S1 + 1;
  2938.         S2 := S2 + 1;
  2939.  
  2940.         -- done if we have exhausted the count
  2941.         Count := Count - 1;
  2942.         exit when Count = 0;
  2943.  
  2944.         -- done if we are past the ends of both strings
  2945.         exit when S1 > String1'LAST and S2 > String2'LAST;
  2946.  
  2947.         -- we can determine the result if we are past the
  2948.         -- end of String1 but not String2
  2949.         if S1 > String1'LAST then
  2950.           if String2(S2) /= ASCII.NUL then
  2951.             Result := LESS_THAN;
  2952.           end if;
  2953.           exit;
  2954.         end if;
  2955.  
  2956.         -- we can determine the result if we are past the
  2957.         -- end of String2 but not String1
  2958.         if S2 > String2'LAST then
  2959.           if String1(S2) /= ASCII.NUL then
  2960.             Result := GREATER_THAN;
  2961.           end if;
  2962.           exit;
  2963.         end if;
  2964.         Loop_Exit := TRUE;  -- indicates normal exit of loop
  2965.       end loop;
  2966.  
  2967.       -- we have exited the loop either normally or abnormally
  2968.       -- (abnormally is via an exit statement); if normally,
  2969.       -- then we have reached the end of String1 and the result
  2970.       -- is EQUAL_TO unless we have also reached the end of
  2971.       -- String2
  2972.       if Loop_Exit and (Count > 0) then
  2973.         if String2(S2) /= ASCII.NUL then
  2974.           Result := LESS_THAN;
  2975.         end if;
  2976.       end if;
  2977.     else
  2978.  
  2979.       -- one of the strings is empty, so determine the
  2980.       -- result (Result is already EQUAL_TO, so if either
  2981.       -- string has some length, then Result changes)
  2982.       if Count > 0 then  -- proceed only if Count > 0
  2983.         if String1'LENGTH > 0 then
  2984.           Result := GREATER_THAN;
  2985.         elsif String2'LENGTH > 0 then
  2986.           Result := LESS_THAN;
  2987.         end if;
  2988.       end if;
  2989.     end if;
  2990.  
  2991.     -- Result is the answer
  2992.     return Result;
  2993.   end Strncmp;
  2994.  
  2995.   -- ...................................................
  2996.   -- .                                                 .
  2997.   -- .  CStrings.Strcasecmp                            .  BODY
  2998.   -- .                                                 .
  2999.   -- ...................................................
  3000.   function Strcasecmp (String1 : in STRING;
  3001.                        String2 : in STRING)
  3002.       return COMPARISON_RESULT is
  3003.   --| Notes
  3004.   --|   This is not commented well because the same
  3005.   --| comments as in Strcmp apply except that Toupper
  3006.   --| is always called on the characters being compared
  3007.     Result : COMPARISON_RESULT := EQUAL_TO;
  3008.     S1 : NATURAL := String1'FIRST;
  3009.     S2 : NATURAL := String2'FIRST;
  3010.     Loop_Exit : BOOLEAN;
  3011.   begin
  3012.     if String1'LENGTH > 0 and String2'LENGTH > 0 then
  3013.       while String1(S1) /= ASCII.NUL loop
  3014.         Loop_Exit := FALSE;
  3015.         if Toupper(String1(S1)) /= Toupper(String2(S2)) then
  3016.           if Toupper(String1(S1)) < Toupper(String2(S2)) then
  3017.             Result := LESS_THAN;
  3018.           else
  3019.             Result := GREATER_THAN;
  3020.           end if;
  3021.           exit;
  3022.         end if;
  3023.         S1 := S1 + 1;
  3024.         S2 := S2 + 1;
  3025.         exit when S1 > String1'LAST and S2 > String2'LAST;
  3026.         if S1 > String1'LAST then
  3027.           if String2(S2) /= ASCII.NUL then
  3028.             Result := LESS_THAN;
  3029.           end if;
  3030.           exit;
  3031.         end if;
  3032.         if S2 > String2'LAST then
  3033.           if String1(S1) /= ASCII.NUL then
  3034.             Result := GREATER_THAN;
  3035.           end if;
  3036.           exit;
  3037.         end if;
  3038.         Loop_Exit := TRUE;
  3039.       end loop;
  3040.       if Loop_Exit then
  3041.         if String2(S2) /= ASCII.NUL then
  3042.           Result := LESS_THAN;
  3043.         end if;
  3044.       end if;
  3045.     else
  3046.       if String1'LENGTH > 0 then
  3047.         Result := GREATER_THAN;
  3048.       elsif String2'LENGTH > 0 then
  3049.         Result := LESS_THAN;
  3050.       end if;
  3051.     end if;    
  3052.     return Result;
  3053.   end Strcasecmp;
  3054.  
  3055.   -- ...................................................
  3056.   -- .                                                 .
  3057.   -- .  CStrings.Strncasecmp                           .  BODY
  3058.   -- .                                                 .
  3059.   -- ...................................................
  3060.   function Strncasecmp (String1 : in STRING;
  3061.                         String2 : in STRING;
  3062.                         Length  : in NATURAL)
  3063.       return COMPARISON_RESULT is
  3064.   --| Notes
  3065.   --|   This is not commented well because the same
  3066.   --| comments as in Strncmp apply except that Toupper
  3067.   --| is always called on the characters being compared
  3068.     Result : COMPARISON_RESULT := EQUAL_TO;
  3069.     S1 : NATURAL := String1'FIRST;
  3070.     S2 : NATURAL := String2'FIRST;
  3071.     Count : NATURAL := Length;
  3072.     Loop_Exit : BOOLEAN;
  3073.   begin
  3074.     if (String1'LENGTH > 0 and String2'LENGTH > 0) and
  3075.        (Count > 0) then
  3076.       while String1(S1) /= ASCII.NUL loop
  3077.         Loop_Exit := FALSE;
  3078.         if Toupper(String1(S1)) /= Toupper(String2(S2)) then
  3079.           if Toupper(String1(S1)) < Toupper(String2(S2)) then
  3080.             Result := LESS_THAN;
  3081.           else
  3082.             Result := GREATER_THAN;
  3083.           end if;
  3084.           exit;
  3085.         end if;
  3086.         S1 := S1 + 1;
  3087.         S2 := S2 + 1;
  3088.         Count := Count - 1;
  3089.         exit when Count = 0;
  3090.         exit when S1 > String1'LAST and S2 > String2'LAST;
  3091.         if S1 > String1'LAST then
  3092.           if String2(S2) /= ASCII.NUL then
  3093.             Result := LESS_THAN;
  3094.           end if;
  3095.           exit;
  3096.         end if;
  3097.         if S2 > String2'LAST then
  3098.           if String1(S1) /= ASCII.NUL then
  3099.             Result := GREATER_THAN;
  3100.           end if;
  3101.           exit;
  3102.         end if;
  3103.         Loop_Exit := TRUE;
  3104.       end loop;
  3105.       if Loop_Exit and (Count > 0) then
  3106.         if String2(S2) /= ASCII.NUL then
  3107.           Result := LESS_THAN;
  3108.         end if;
  3109.       end if;
  3110.     else
  3111.       if Count > 0 then
  3112.         if String1'LENGTH > 0 then
  3113.           Result := GREATER_THAN;
  3114.         elsif String2'LENGTH > 0 then
  3115.           Result := LESS_THAN;
  3116.         end if;
  3117.       end if;
  3118.     end if;    
  3119.     return Result;
  3120.   end Strncasecmp;
  3121.  
  3122.   -- ...................................................
  3123.   -- .                                                 .
  3124.   -- .  CStrings.Strcpy                                .  BODY
  3125.   -- .                                                 .
  3126.   -- ...................................................
  3127.   procedure Strcpy (From : in STRING;
  3128.                     To   : out STRING) is
  3129.   begin
  3130.     Copy(From, To, To'FIRST);
  3131.   exception
  3132.     when others => raise LENGTH_ERROR;
  3133.   end Strcpy;
  3134.  
  3135.   -- ...................................................
  3136.   -- .                                                 .
  3137.   -- .  CStrings.Strncpy                               .  BODY
  3138.   -- .                                                 .
  3139.   -- ...................................................
  3140.   procedure Strncpy (From   : in STRING;
  3141.                      To     : out STRING;
  3142.                      Length : in NATURAL) is
  3143.     S     : NATURAL := From'FIRST;
  3144.     D     : NATURAL := To'FIRST;
  3145.     Count : NATURAL := Length;
  3146.   begin
  3147.  
  3148.     -- do not attempt copy if From is empty
  3149.     if From'LENGTH > 0 then
  3150.  
  3151.       -- perform a char-for-char copy, checking for
  3152.       -- ASCII.NUL, end of From buffer, and end of Count
  3153.       while From(S) /= ASCII.NUL loop
  3154.         To(D) := From(S);
  3155.         D := D + 1;
  3156.         S := S + 1;
  3157.         exit when S > From'LAST;
  3158.         Count := Count - 1;
  3159.         exit when Count = 0;
  3160.       end loop;
  3161.     end if;
  3162.     To(D) := ASCII.NUL;
  3163.   exception
  3164.     when others => raise LENGTH_ERROR;
  3165.   end Strncpy;
  3166.  
  3167.   -- ...................................................
  3168.   -- .                                                 .
  3169.   -- .  CStrings.Strlen                                .  BODY
  3170.   -- .                                                 .
  3171.   -- ...................................................
  3172.   function Strlen (String1 : in STRING) return NATURAL is
  3173.     Result : NATURAL := 0;
  3174.     S      : NATURAL := String1'FIRST;
  3175.   begin
  3176.     if S <= String1'LAST then
  3177.       while String1(S) /= ASCII.NUL loop
  3178.         Result := Result + 1;
  3179.         S := S + 1;
  3180.         exit when S > String1'LAST;
  3181.       end loop;
  3182.     end if;
  3183.     return Result;
  3184.   end Strlen;
  3185.  
  3186.   -- ...................................................
  3187.   -- .                                                 .
  3188.   -- .  CStrings.Strchr                                .  BODY
  3189.   -- .                                                 .
  3190.   -- ...................................................
  3191.   function Strchr (String1 : in STRING;
  3192.                    Char1   : in CHARACTER) return NATURAL is
  3193.     Result : NATURAL := 0;
  3194.     S      : NATURAL := String1'FIRST;
  3195.   begin
  3196.     if String1'LENGTH > 0 then
  3197.       -- if String1 is not empty, do char-by-char
  3198.       -- compare
  3199.       while String1(S) /= ASCII.NUL loop
  3200.         if String1(S) = Char1 then
  3201.           Result := S;
  3202.           exit;
  3203.         end if;
  3204.         S := S + 1;
  3205.         exit when S > String1'LAST;
  3206.       end loop;
  3207.     end if;
  3208.     return Result;
  3209.   end Strchr;
  3210.  
  3211.   -- ...................................................
  3212.   -- .                                                 .
  3213.   -- .  CStrings.Strrchr                               .  BODY
  3214.   -- .                                                 .
  3215.   -- ...................................................
  3216.   function Strrchr (String1 : in STRING;
  3217.                     Char1   : in CHARACTER) return NATURAL is
  3218.     Result : NATURAL := 0;
  3219.     S      : NATURAL;
  3220.   begin
  3221.     S := Strlen(String1);
  3222.     if S > 0 then
  3223.       -- search only if the string is not empty
  3224.       S := String1'FIRST + Strlen(String1) - 1;  -- index of last char
  3225.       loop
  3226.         if String1(S) = Char1 then
  3227.           Result := S;
  3228.           exit;
  3229.         end if;
  3230.         exit when S = String1'FIRST;
  3231.         S := S - 1;
  3232.       end loop;
  3233.     end if;
  3234.     return Result;
  3235.   end Strrchr;
  3236.  
  3237.   -- ...................................................
  3238.   -- .                                                 .
  3239.   -- .  CStrings.Strpbrk                               .  BODY
  3240.   -- .                                                 .
  3241.   -- ...................................................
  3242.   function Strpbrk (String1 : in STRING;
  3243.                     String2 : in STRING) return NATURAL is
  3244.     Result : NATURAL := 0;
  3245.     S1     : NATURAL := String1'FIRST;
  3246.   begin
  3247.     if String1'LENGTH > 0 then
  3248.       -- search only if String1 is not empty
  3249.       while String1(S1) /= ASCII.NUL loop
  3250.         if Char_is_in_String (String1(S1), String2) then
  3251.           Result := S1;
  3252.           exit;
  3253.         end if;
  3254.         S1 := S1 + 1;
  3255.         exit when S1 > String1'LAST;
  3256.       end loop;
  3257.     end if;
  3258.     return Result;
  3259.   end Strpbrk;
  3260.  
  3261.   -- ...................................................
  3262.   -- .                                                 .
  3263.   -- .  CStrings.Strspn                                .  BODY
  3264.   -- .                                                 .
  3265.   -- ...................................................
  3266.   function Strspn (String1 : in STRING;
  3267.                    String2 : in STRING) return NATURAL is
  3268.     S1     : NATURAL := String1'FIRST;
  3269.     Result : NATURAL := 0;
  3270.   begin
  3271.     if String1'LENGTH > 0 then
  3272.  
  3273.       -- search only if String1 is not empty
  3274.       while String1(S1) /= ASCII.NUL loop
  3275.         if Char_is_in_String (String1(S1), String2) then
  3276.           Result := 1;
  3277.           S1 := S1 + 1;
  3278.           exit;
  3279.         end if;
  3280.         S1 := S1 + 1;
  3281.         exit when S1 > String1'LAST;
  3282.       end loop;
  3283.  
  3284.       -- at this point, Result=1 if we found a char
  3285.       if Result = 1 and S1 <= String1'LAST then
  3286.         -- we have found one of the chars and are not done,
  3287.         -- so look for rest of the chars
  3288.         while String1(S1) /= ASCII.NUL loop
  3289.           if Char_is_in_String (String1(S1), String2) then
  3290.             Result := Result + 1;
  3291.           else
  3292.             exit;
  3293.           end if;
  3294.           S1 := S1 + 1;
  3295.           exit when S1 > String1'LAST;
  3296.         end loop;
  3297.       end if;
  3298.     end if;
  3299.     return Result;
  3300.   end Strspn;
  3301.  
  3302.   -- ...................................................
  3303.   -- .                                                 .
  3304.   -- .  CStrings.Strcspn                               .  BODY
  3305.   -- .                                                 .
  3306.   -- ...................................................
  3307.   function Strcspn (String1 : in STRING;
  3308.                     String2 : in STRING) return NATURAL is
  3309.     S1     : NATURAL := String1'First;
  3310.     Result : NATURAL := 0;
  3311.   begin
  3312.     if String1'LENGTH > 0 then
  3313.  
  3314.       -- do this only if String1 is not empty
  3315.       while String1(S1) /= ASCII.NUL loop
  3316.         if not Char_is_in_String (String1(S1), String2) then
  3317.           Result := 1;
  3318.           S1 := S1 + 1;
  3319.           exit;
  3320.         end if;
  3321.         S1 := S1 + 1;
  3322.         exit when S1 > String1'LAST;
  3323.       end loop;
  3324.  
  3325.       -- Result=1 means we have not found one of the chars
  3326.       if Result = 1 and S1 <= String1'LAST then
  3327.  
  3328.         -- look for limit to non-matching string
  3329.         while String1(S1) /= ASCII.NUL loop
  3330.           if not Char_is_in_String (String1(S1), String2) then
  3331.             Result := Result + 1;
  3332.           else
  3333.             exit;
  3334.           end if;
  3335.           S1 := S1 + 1;
  3336.           exit when S1 > String1'LAST;
  3337.         end loop;
  3338.       end if;
  3339.     end if;
  3340.     return Result;
  3341.   end Strcspn;
  3342.  
  3343.   -- ...................................................
  3344.   -- .                                                 .
  3345.   -- .  CStrings.Strtok                                .  BODY
  3346.   -- .                                                 .
  3347.   -- ...................................................
  3348.   procedure Strtok (Target     : in STRING;
  3349.                     Start      : in out NATURAL;
  3350.                     Delimiters : in STRING;
  3351.                     Next_Token : out STRING) is
  3352.     Next_Rover   : NATURAL := Next_Token'FIRST;
  3353.   begin
  3354.     if Start > Target'LAST then
  3355.  
  3356.       -- Done if past the end of the string
  3357.       Next_Token(Next_Rover) := ASCII.NUL;
  3358.     else
  3359.  
  3360.       -- skip over leading delimiters
  3361.       while Start <= Target'LAST and then
  3362.             (Char_is_in_String (Target(Start), Delimiters) and
  3363.              Target(Start) /= ASCII.NUL) loop
  3364.         Start := Start + 1;
  3365.       end loop;
  3366.  
  3367.       -- Start is now index of first char, so begin extraction
  3368.       -- of token into Next_Token buffer
  3369.       while Start <= Target'LAST and then
  3370.             (not Char_is_in_String (Target(Start), Delimiters) and
  3371.              Target(Start) /= ASCII.NUL) loop
  3372.         Next_Token(Next_Rover) := Target(Start);
  3373.         Next_Rover := Next_Rover + 1;
  3374.         Start := Start + 1;
  3375.         exit when Start > Target'LAST;
  3376.       end loop;
  3377.  
  3378.       -- Start is either index of delimiter after last char
  3379.       -- of token or index of ASCII.NUL after Target string
  3380.       Next_Token(Next_Rover) := ASCII.NUL;
  3381.     end if;
  3382.   exception
  3383.     when others => raise LENGTH_ERROR;
  3384.   end Strtok;
  3385.  
  3386. end CStrings;
  3387. --::::::::::
  3388. --darray.bdy
  3389. --::::::::::
  3390. with unchecked_deallocation;
  3391.  
  3392. package body darray_pkg is
  3393.  
  3394.     -- Utilities:
  3395.  
  3396.     procedure free_array_ptr is
  3397.         new unchecked_deallocation(array_type, array_ptr);
  3398.  
  3399.     procedure free_darray is
  3400.     new unchecked_deallocation(darray_info, darray);
  3401.     
  3402.     function down_index(i: integer;
  3403.                         d: darray)
  3404.         return integer;
  3405.  
  3406.       --| Raises: out_of_bounds
  3407.       --| Effects:
  3408.       --| Map from abstraction indices to representation indices.
  3409.       --| Raises out_of_bounds iff either is_empty(d) or i is not in
  3410.       --| d.first..last(d).
  3411.       --| Requires: d must be initialized.
  3412.  
  3413.     procedure initialization_check(d: darray);
  3414.     
  3415.       --| Raises: uninitialized_darray
  3416.       --| Effects:
  3417.       --| Returns normally iff d has been the target of a create, copy,
  3418.       --| or array_to_darray operation, and has not since been destroyed.
  3419.       --| Otherwise, raises uninitialized_darray.
  3420.       --| This procedure will not detect the case where another object
  3421.       --| sharing the same darray value has been destroyed; this is
  3422.       --| erroneous use.
  3423.  
  3424.     procedure expand(d: in out darray);
  3425.     
  3426.       --| Effects:
  3427.       --| Allocates additional space in d.arr.  The old contents of d.arr
  3428.       --| are copied to a slice of the new array.  The expansion amount is
  3429.       --| a percentage (d.expand_percent) of currently allocated space.
  3430.       --| Sets d.first_idx and d.last_idx to appropriate positions in the
  3431.       --| new array; these positions are selected according to the
  3432.       --| expected distribution of add_highs/add_lows (d.high_percent).
  3433.       --| Requires: d must be initialized.
  3434.  
  3435.     procedure contract(d: in out darray);
  3436.     
  3437.       --| Effects:
  3438.       --| Checks whether d.arr consumes too much space in proportion to
  3439.       --| the slice that is being used to hold the darray elements.  If
  3440.       --| so, halves the size of d.arr.  The old contents of d.arr are
  3441.       --| copied to a slice of the new array.  Sets d.first_idx and
  3442.       --| and d.last_idx to appropriate positions in the new array; these
  3443.       --| positions are selected according to the expected distribution of
  3444.       --| add_highs/add_lows (d.high_percent).
  3445.       --| Requires: d must be initialized and nonempty.
  3446.       
  3447.     procedure reallocate(d:          in out darray;
  3448.              new_length: in     positive);
  3449.  
  3450.       --| Raises: out_of_bounds
  3451.       --| Effects:
  3452.       --| Replaces d.arr with a pointer to an array of length new_length,
  3453.       --| fills a slice of this array with the old contents of d.arr, and
  3454.       --| adjusts d.first_idx and d.last_idx appropriately.  Everything is
  3455.       --| done according to d.high_percent.  Used by both expand/contract.
  3456.       --| Raises out_of_bounds iff new_length < length(d).
  3457.       --| Requires: d must be initialized.
  3458.  
  3459.     procedure determine_position(array_length: in  positive;
  3460.                                  slice_length: in  natural;
  3461.                                  high_percent: in  positive;
  3462.                  first_idx:    out positive;
  3463.                  last_idx:     out natural);
  3464.                  
  3465.       --| Raises: out_of_bounds
  3466.       --| Effects:
  3467.       --| Determines the appropriate position of a slice of length
  3468.       --| slice_length in an array with range 1..array_length.  This
  3469.       --| position is calculated according to the high_percent parameter.
  3470.       --| Raises out_of_bounds iff slice_length > array_length.
  3471.       --| Used by create, array_to_darray, reallocate.
  3472.  
  3473.  
  3474.   -- Constructors:
  3475.  
  3476.     procedure create(first:          in     integer := 1;
  3477.                      predict:        in     positive := default_predict;
  3478.                      high_percent:   in     positive := default_high;
  3479.                      expand_percent: in     positive := default_expand;
  3480.                      d:              in out darray) is
  3481.     begin
  3482.         destroy(d);
  3483.     d := new darray_info;
  3484.         determine_position(predict, 0, high_percent,
  3485.                d.first_idx, d.last_idx);
  3486.         d.first := first;
  3487.         d.high_percent := high_percent;
  3488.         d.expand_percent := expand_percent;
  3489.         d.arr := new array_type(1..predict);
  3490.     exception
  3491.         when out_of_bounds =>    -- determine_position fails
  3492.         destroy(d);
  3493.         raise;
  3494.     end create;
  3495.  
  3496.     procedure array_to_darray(a:              in    array_type;
  3497.                               first:          in    integer:= 1;
  3498.                               predict:        in    positive;
  3499.                               high_percent:   in    positive
  3500.                                                        := default_high;
  3501.                               expand_percent: in    positive
  3502.                                                        := default_expand;
  3503.                               d:              in out darray) is
  3504.     begin
  3505.         free_array_ptr(d.arr);
  3506.     d := new darray_info;
  3507.         determine_position(predict, a'length, high_percent,
  3508.                d.first_idx, d.last_idx);
  3509.         d.first := first;
  3510.         d.high_percent := high_percent;
  3511.         d.expand_percent := expand_percent;
  3512.         d.arr := new array_type(1..predict);
  3513.         d.arr.all := a;
  3514.     exception
  3515.         when out_of_bounds =>     -- determine_position fails
  3516.         destroy(d);
  3517.         raise;
  3518.     end array_to_darray;
  3519.  
  3520.     procedure set_first(d:     in out darray;
  3521.                         first: in     integer) is
  3522.     begin
  3523.         initialization_check(d);
  3524.         d.first := first;
  3525.     end set_first;
  3526.  
  3527.     procedure add_low(d: in out darray;
  3528.                       e: in     elem_type) is
  3529.     begin
  3530.         initialization_check(d);
  3531.         d.arr(d.first_idx - 1) := e;
  3532.         d.first_idx := d.first_idx - 1;
  3533.         d.first := d.first - 1;
  3534.     exception
  3535.         when constraint_error =>    -- on array store
  3536.             expand(d);
  3537.             d.arr(d.first_idx - 1) := e;
  3538.             d.first_idx := d.first_idx - 1;
  3539.             d.first := d.first - 1;
  3540.     end add_low;
  3541.  
  3542.     procedure add_high(d: in out darray;
  3543.                        e: in     elem_type) is
  3544.     begin
  3545.         initialization_check(d);
  3546.         d.arr(d.last_idx + 1) := e;
  3547.         d.last_idx := d.last_idx + 1;
  3548.     exception
  3549.         when constraint_error =>    -- on array store
  3550.             expand(d);
  3551.             d.arr(d.last_idx + 1) := e;
  3552.             d.last_idx := d.last_idx + 1;
  3553.     end add_high;
  3554.  
  3555.     procedure remove_low(d: in out darray) is
  3556.     begin
  3557.         initialization_check(d);
  3558.     if d.last_idx < d.first_idx then raise out_of_bounds; end if;
  3559.     
  3560.     d.first_idx := d.first_idx + 1;
  3561.     d.first := d.first + 1;
  3562.     contract(d);
  3563.     end remove_low;
  3564.  
  3565.     procedure remove_high(d: in out darray) is
  3566.     begin
  3567.         initialization_check(d);
  3568.         if d.last_idx < d.first_idx then raise out_of_bounds; end if;
  3569.     
  3570.         d.last_idx := d.last_idx - 1;
  3571.         contract(d);
  3572.     end remove_high;
  3573.  
  3574.     procedure store(d: in out darray;
  3575.                     i: in     integer;
  3576.                     e: in     elem_type) is
  3577.     begin
  3578.         initialization_check(d);
  3579.         d.arr(down_index(i, d)) := e;
  3580.     end store;
  3581.     
  3582.    function copy(d: darray)
  3583.        return darray is
  3584.        d2: darray;
  3585.    begin
  3586.        initialization_check(d);
  3587.        d2 := new darray_info'(first_idx => d.first_idx,
  3588.                   last_idx => d.last_idx,
  3589.                   first => d.first,
  3590.                   high_percent => d.high_percent,
  3591.                   expand_percent => d.expand_percent,
  3592.                   arr => new array_type(1..d.arr'length));
  3593.        d2.arr.all := d.arr.all;
  3594.        return d2;
  3595.     end copy;
  3596.  
  3597.     function copy_deep(d: darray)
  3598.     return darray is
  3599.     d2: darray;
  3600.     begin
  3601.     initialization_check(d);
  3602.     d2 := new darray_info'(first_idx => d.first_idx,
  3603.                    last_idx => d.last_idx,
  3604.                    first => d.first,
  3605.                    high_percent => d.high_percent,
  3606.                    expand_percent => d.expand_percent,
  3607.                    arr => new array_type(1..d.arr'length));
  3608.     for i in d.first_idx..d.last_idx loop
  3609.         d2.arr(i) := copy(d.arr(i));
  3610.     end loop;
  3611.     return d2;
  3612.      end copy_deep;
  3613.  
  3614.  
  3615.   -- Query Operations:
  3616.  
  3617.     function fetch(d: darray;
  3618.                    i: integer)
  3619.         return elem_type is
  3620.     begin
  3621.         initialization_check(d);
  3622.         return d.arr(down_index(i, d));
  3623.     end fetch;
  3624.  
  3625.     function low(d: in darray)
  3626.         return elem_type is
  3627.     begin
  3628.         initialization_check(d);
  3629.         return d.arr(down_index(d.first, d));
  3630.     end low;
  3631.  
  3632.     function high(d: in darray)
  3633.         return elem_type is
  3634.     begin
  3635.         if is_empty(d) then      -- is_empty checks for initialization
  3636.             raise out_of_bounds;
  3637.         end if;
  3638.         return d.arr(d.last_idx);
  3639.     end high;
  3640.  
  3641.     function first(d: in darray)
  3642.         return integer is
  3643.     begin
  3644.         initialization_check(d);
  3645.         return d.first;
  3646.     end first;
  3647.  
  3648.     function last(d: in darray)
  3649.         return integer is
  3650.     begin
  3651.         initialization_check(d);
  3652.         return d.first + d.last_idx - d.first_idx;
  3653.     end last;
  3654.  
  3655.     function is_empty(d: in darray)
  3656.         return boolean is
  3657.     begin
  3658.         initialization_check(d);
  3659.         return d.last_idx < d.first_idx;
  3660.     end is_empty;
  3661.  
  3662.     function length(d: in darray)
  3663.         return natural is
  3664.     begin
  3665.         initialization_check(d);
  3666.         return d.last_idx - d.first_idx + 1;
  3667.     end length;
  3668.  
  3669.     function equal(d1, d2: darray)
  3670.         return boolean is
  3671.     i2: integer;
  3672.     begin
  3673.         initialization_check(d1);
  3674.         initialization_check(d2);
  3675.  
  3676.         if d1.first /= d2.first or else length(d1) /= length(d2) then
  3677.             return false;
  3678.         end if;
  3679.  
  3680.     i2 := d2.first_idx;
  3681.     for i1 in d1.first_idx..d1.last_idx loop
  3682.         if not equal(d1.arr(i1), d2.arr(i2)) then
  3683.         return false;
  3684.         end if;
  3685.         i2 := i2 + 1;
  3686.     end loop;
  3687.  
  3688.     return true;
  3689.     end equal;
  3690.  
  3691.     function darray_to_array(d: darray)
  3692.         return array_type is
  3693.         subtype dbounds_array is array_type(d.first..last(d));
  3694.         -- invocation of last performs initialization check.
  3695.     begin
  3696.         return dbounds_array'(d.arr(d.first_idx..d.last_idx));
  3697.     end darray_to_array;
  3698.  
  3699.  
  3700.   -- Iterators:
  3701.  
  3702.     function make_elements_iter(d: darray)
  3703.         return elements_iter is
  3704.     begin
  3705.         initialization_check(d);
  3706.         return (current => d.first_idx,
  3707.                 last => d.last_idx,
  3708.                 arr => d.arr);
  3709.     end make_elements_iter;
  3710.  
  3711.     function more(iter: elements_iter)
  3712.         return boolean is
  3713.     begin
  3714.         return iter.current <= iter.last;
  3715.     end more;
  3716.  
  3717.     procedure next(iter: in out elements_iter;
  3718.                    e:       out elem_type) is
  3719.     begin
  3720.         if not more(iter) then raise no_more; end if;
  3721.  
  3722.         e := iter.arr(iter.current);
  3723.         iter.current := iter.current + 1;
  3724.     end next;
  3725.  
  3726.       
  3727.     -- Heap Management:
  3728.  
  3729.     procedure destroy(d: in out darray) is
  3730.     begin
  3731.         free_array_ptr(d.arr);
  3732.     free_darray(d);
  3733.     exception
  3734.         when constraint_error =>    -- d is null, d.arr is illegal.
  3735.             return;
  3736.     end destroy;
  3737.  
  3738.  
  3739.     -- Utilities:
  3740.  
  3741.     function down_index(i: integer;
  3742.                         d: darray)
  3743.         return integer is
  3744.         down_idx: integer := i - d.first + d.first_idx;
  3745.     begin
  3746.         if d.last_idx < d.first_idx or else                -- empty array
  3747.            not (down_idx in d.first_idx..d.last_idx) then  -- bogus index
  3748.             raise out_of_bounds;
  3749.         end if;
  3750.  
  3751.         return down_idx;
  3752.     end down_index;
  3753.  
  3754.     procedure initialization_check(d: darray) is
  3755.     begin
  3756.         if d = null then raise uninitialized_darray; end if;
  3757.     end initialization_check;
  3758.  
  3759.     procedure expand(d: in out darray) is
  3760.         new_length: integer :=
  3761.         (d.arr'length * (100 + d.expand_percent))/100;
  3762.     begin
  3763.         -- Specified percent, in relation to length, may be too small to
  3764.     -- force any growth.  In this case, force growth.  This is rare.
  3765.     -- The choice to double is arbitrary.
  3766.     
  3767.     if new_length = d.arr'length then
  3768.         new_length := 2 * d.arr'length;
  3769.     end if;
  3770.  
  3771.         reallocate(d, new_length);
  3772.     end expand;
  3773.  
  3774.     procedure contract(d: in out darray) is
  3775.       -- <<A better contraction strategy is needed.  Justification is weak
  3776.       -- for this one.>>
  3777.     begin
  3778.         null;
  3779.     end contract;
  3780.  
  3781.     procedure reallocate(d:          in out darray;
  3782.              new_length: in     positive) is
  3783.                  
  3784.     new_arr: array_ptr;
  3785.     new_first_idx: integer;
  3786.     new_last_idx: integer;
  3787.  
  3788.     begin
  3789.         determine_position(new_length, length(d), d.high_percent,
  3790.                new_first_idx, new_last_idx);
  3791.     new_arr := new array_type(1..new_length);
  3792.     new_arr(new_first_idx..new_last_idx) :=
  3793.         d.arr(d.first_idx..d.last_idx);
  3794.     free_array_ptr(d.arr);
  3795.     d.arr := new_arr;
  3796.     d.first_idx := new_first_idx;
  3797.     d.last_idx := new_last_idx;
  3798.     end reallocate;
  3799.     
  3800.     procedure determine_position(array_length: in  positive;
  3801.                                  slice_length: in  natural;
  3802.                                  high_percent: in  positive;
  3803.                  first_idx:    out positive;
  3804.                  last_idx:     out natural) is
  3805.                    
  3806.         left_over: integer := array_length - slice_length;
  3807.         high_space: integer := (high_percent * left_over)/100;
  3808.         low_space: integer := left_over - high_space;
  3809.     
  3810.     begin
  3811.     if left_over < 0 then raise out_of_bounds; end if;
  3812.     
  3813.         first_idx := low_space + 1;
  3814.         last_idx := low_space + slice_length;
  3815.     end determine_position;
  3816.     
  3817. end darray_pkg;
  3818. --::::::::::
  3819. --dlist.bdy
  3820. --::::::::::
  3821. package body DOUBLY_LINKED_LIST is
  3822.    
  3823.    --=======================================================================
  3824.    -- General-purpose routines
  3825.    --=======================================================================
  3826.    procedure ALLOCATE (ID     : in out LIST_ID;
  3827.                        ITEM   : in ELEMENT_OBJECT;
  3828.                        RESULT : out ELEMENT_POINTER) is
  3829.       NEW_ELEMENT : ELEMENT_POINTER;
  3830.    begin
  3831.       if ID.FREE = null then
  3832.          NEW_ELEMENT := new ELEMENT'(CONTENT  => ITEM, 
  3833.                                      NEXT     => null, 
  3834.                                      PREVIOUS => null);
  3835.       else
  3836.          NEW_ELEMENT          := ID.FREE;
  3837.          ID.FREE              := NEW_ELEMENT.NEXT;
  3838.          NEW_ELEMENT.CONTENT  := ITEM;
  3839.          NEW_ELEMENT.NEXT     := null;
  3840.          NEW_ELEMENT.PREVIOUS := null;
  3841.       end if;
  3842.       RESULT := NEW_ELEMENT;
  3843.    exception
  3844.       when others    =>
  3845.          raise DYNAMIC_MEMORY_ALLOCATION_PROBLEM;
  3846.    end ALLOCATE;
  3847.    
  3848.    procedure ADD_TO_FREE (ID   : in out LIST_ID;
  3849.                           ITEM : in ELEMENT_POINTER) is
  3850.    begin
  3851.       if ID.FREE = null then
  3852.          ID.FREE      := ITEM;
  3853.          ID.FREE.NEXT := null;
  3854.       else
  3855.          ITEM.NEXT := ID.FREE;
  3856.          ID.FREE   := ITEM;
  3857.       end if;
  3858.    end ADD_TO_FREE;
  3859.    
  3860.    --=======================================================================
  3861.    -- Initialize
  3862.    --=======================================================================
  3863.    procedure INITIALIZE (ID : in out LIST_ID) is
  3864.       
  3865.       --=========================== PDL ==============================
  3866.       --|ABSTRACT:
  3867.       --|    INITIALIZE initializes the list to empty.  If the list
  3868.       --|    contained any elements, they are prefixed to the free
  3869.       --|    list.
  3870.       --|DESIGN DESCRIPTION:
  3871.       --|    If the free list is empty (FREE is NULL)
  3872.       --|        Set FREE to point to the first element (FIRST)
  3873.       --|    Else
  3874.       --|        If the current list is not empty (FIRST /= NULL)
  3875.       --|            Set LAST.NEXT to point to the free list (FREE)
  3876.       --|            Set FREE to point to the old list (FIRST)
  3877.       --|        End if
  3878.       --|    End if
  3879.       --|    Set FIRST to NULL
  3880.       --|    Set LAST to NULL
  3881.       --|    Set CURRENT to NULL
  3882.       --|    Set NUMBER_OF_ELEMENTS to 0
  3883.       --|    Set CURRENT_INDEX to 0
  3884.       --==============================================================
  3885.       
  3886.    begin
  3887.       if ID.FREE = null then
  3888.          ID.FREE := ID.FIRST;
  3889.       else
  3890.          if ID.FIRST /= null then
  3891.             ID.LAST.NEXT := ID.FREE;
  3892.             ID.FREE      := ID.FIRST;
  3893.          end if;
  3894.       end if;
  3895.       ID.FIRST              := null;
  3896.       ID.LAST               := null;
  3897.       ID.CURRENT            := null;
  3898.       ID.NUMBER_OF_ELEMENTS := 0;
  3899.       ID.CURRENT_INDEX      := 0;
  3900.    end INITIALIZE;
  3901.    
  3902.    --=======================================================================
  3903.    -- Return elements from the list
  3904.    --=======================================================================
  3905.    function FIRST_ELEMENT (ID : in LIST_ID) return ELEMENT_OBJECT is
  3906.       
  3907.       --=========================== PDL ==============================
  3908.       --|ABSTRACT:
  3909.       --|    FIRST_ELEMENT returns the value (content) of the first
  3910.       --|    element in the linked list.
  3911.       --|DESIGN DESCRIPTION:
  3912.       --|    If the list is empty (IS_EMPTY), raise LIST_IS_EMPTY
  3913.       --|    Return the first element of the list
  3914.       --==============================================================
  3915.       
  3916.    begin
  3917.       if IS_EMPTY (ID) then
  3918.          raise LIST_IS_EMPTY;
  3919.       end if;
  3920.       return ID.FIRST.CONTENT;
  3921.       
  3922.    exception
  3923.       when LIST_IS_EMPTY  =>
  3924.          raise ;
  3925.       when others    =>
  3926.          raise UNEXPECTED_ERROR;
  3927.    end FIRST_ELEMENT;
  3928.    
  3929.    function LAST_ELEMENT (ID : in LIST_ID) return ELEMENT_OBJECT is
  3930.       
  3931.       --=========================== PDL ==============================
  3932.       --|ABSTRACT:
  3933.       --|    LAST_ELEMENT returns the value (content) of the last
  3934.       --|    element in the linked list.
  3935.       --|DESIGN DESCRIPTION:
  3936.       --|    If the list is empty (IS_EMPTY), raise LIST_IS_EMPTY
  3937.       --|    Return the last element of the list
  3938.       --==============================================================
  3939.       
  3940.    begin
  3941.       if IS_EMPTY (ID) then
  3942.          raise LIST_IS_EMPTY;
  3943.       end if;
  3944.       return ID.LAST.CONTENT;
  3945.       
  3946.    exception
  3947.       when LIST_IS_EMPTY  =>
  3948.          raise ;
  3949.       when others    =>
  3950.          raise UNEXPECTED_ERROR;
  3951.    end LAST_ELEMENT;
  3952.    
  3953.    function CURRENT_ELEMENT (ID : in LIST_ID) return ELEMENT_OBJECT is
  3954.       
  3955.       --=========================== PDL ==============================
  3956.       --|ABSTRACT:
  3957.       --|    CURRENT_ELEMENT returns the value (content) of the current
  3958.       --|    element in the linked list.
  3959.       --|DESIGN DESCRIPTION:
  3960.       --|    If the list is empty (IS_EMPTY), raise LIST_IS_EMPTY
  3961.       --|    Return the current element of the list
  3962.       --==============================================================
  3963.       
  3964.    begin
  3965.       if IS_EMPTY (ID) then
  3966.          raise LIST_IS_EMPTY;
  3967.       end if;
  3968.       return ID.CURRENT.CONTENT;
  3969.       
  3970.    exception
  3971.       when LIST_IS_EMPTY  =>
  3972.          raise ;
  3973.       when others    =>
  3974.          raise UNEXPECTED_ERROR;
  3975.    end CURRENT_ELEMENT;
  3976.    
  3977.    --=======================================================================
  3978.    -- Position the current element in the list
  3979.    --=======================================================================
  3980.    procedure GOTO_FIRST (ID : in out LIST_ID) is
  3981.       
  3982.       --=========================== PDL ==============================
  3983.       --|ABSTRACT:
  3984.       --|    GOTO_FIRST sets the current element to be the first
  3985.       --|    element in the linked list.
  3986.       --|DESIGN DESCRIPTION:
  3987.       --|    Set CURRENT to FIRST
  3988.       --==============================================================
  3989.       
  3990.    begin
  3991.       if IS_EMPTY (ID) then
  3992.          raise LIST_IS_EMPTY;
  3993.       end if;
  3994.       ID.CURRENT       := ID.FIRST;
  3995.       ID.CURRENT_INDEX := 1;
  3996.       
  3997.    exception
  3998.       when LIST_IS_EMPTY  =>
  3999.          raise ;
  4000.       when others    =>
  4001.          raise UNEXPECTED_ERROR;
  4002.    end GOTO_FIRST;
  4003.    
  4004.    procedure GOTO_LAST (ID : in out LIST_ID) is
  4005.       
  4006.       --=========================== PDL ==============================
  4007.       --|ABSTRACT:
  4008.       --|    GOTO_LAST sets the current element to be the last
  4009.       --|    element in the linked list.
  4010.       --|DESIGN DESCRIPTION:
  4011.       --|    Set CURRENT to LAST
  4012.       --==============================================================
  4013.       
  4014.    begin
  4015.       if IS_EMPTY (ID) then
  4016.          raise LIST_IS_EMPTY;
  4017.       end if;
  4018.       ID.CURRENT       := ID.LAST;
  4019.       ID.CURRENT_INDEX := ID.NUMBER_OF_ELEMENTS;
  4020.       
  4021.    exception
  4022.       when LIST_IS_EMPTY  =>
  4023.          raise ;
  4024.       when others    =>
  4025.          raise UNEXPECTED_ERROR;
  4026.    end GOTO_LAST;
  4027.    
  4028.    procedure GOTO_ELEMENT (ID    : in out LIST_ID;
  4029.                            INDEX : in ELEMENT_POSITION) is
  4030.       
  4031.       --=========================== PDL ==============================
  4032.       --|ABSTRACT:
  4033.       --|    GOTO sets the current element to be the Nth
  4034.       --|    element in the linked list.
  4035.       --|DESIGN DESCRIPTION:
  4036.       --|    If list IS_EMPTY, raise LIST_IS_EMPTY
  4037.       --|    If INDEX > NUMBER_OF_ELEMENTS then raise INVALID_INDEX
  4038.       --|    If INDEX < 1 then raise INVALID_INDEX
  4039.       --|    Set CURRENT to point to the proper element
  4040.       --|    Set CURRENT_INDEX to INDEX
  4041.       --==============================================================
  4042.       
  4043.       ROVER : ELEMENT_POINTER;
  4044.       
  4045.    begin
  4046.       if IS_EMPTY (ID) then
  4047.          raise LIST_IS_EMPTY;
  4048.       end if;
  4049.       if INDEX > ID.NUMBER_OF_ELEMENTS then
  4050.          raise INVALID_INDEX;
  4051.       end if;
  4052.       if INDEX < 1 then
  4053.          raise INVALID_INDEX;
  4054.       end if;
  4055.       ROVER := ID.FIRST;
  4056.       if INDEX > 1 then
  4057.          for I in 1 .. INDEX - 1 loop
  4058.             ROVER := ROVER.NEXT;
  4059.          end loop;
  4060.       end if;
  4061.       ID.CURRENT       := ROVER;
  4062.       ID.CURRENT_INDEX := INDEX;
  4063.       
  4064.    exception
  4065.       when LIST_IS_EMPTY  | INVALID_INDEX     =>
  4066.          raise ;
  4067.       when others    =>
  4068.          raise UNEXPECTED_ERROR;
  4069.    end GOTO_ELEMENT;
  4070.    
  4071.    --=======================================================================
  4072.    -- Return the indices of the current and last elements
  4073.    --=======================================================================
  4074.    function CURRENT_INDEX (ID : in LIST_ID) return ELEMENT_POSITION is
  4075.       
  4076.       --=========================== PDL ==============================
  4077.       --|ABSTRACT:
  4078.       --|    CURRENT_INDEX returns the index number of the current
  4079.       --|    element in the linked list.
  4080.       --|DESIGN DESCRIPTION:
  4081.       --|    If list IS_EMPTY, raise LIST_IS_EMPTY
  4082.       --|    Return CURRENT_INDEX
  4083.       --==============================================================
  4084.       
  4085.    begin
  4086.       if IS_EMPTY (ID) then
  4087.          raise LIST_IS_EMPTY;
  4088.       end if;
  4089.       return ID.CURRENT_INDEX;
  4090.       
  4091.    exception
  4092.       when LIST_IS_EMPTY  =>
  4093.          raise ;
  4094.       when others    =>
  4095.          raise UNEXPECTED_ERROR;
  4096.    end CURRENT_INDEX;
  4097.    
  4098.    function LAST_INDEX (ID : in LIST_ID) return ELEMENT_POSITION is
  4099.       
  4100.       --=========================== PDL ==============================
  4101.       --|ABSTRACT:
  4102.       --|    LAST_INDEX returns the index number of the last
  4103.       --|    element in the linked list.
  4104.       --|DESIGN DESCRIPTION:
  4105.       --|    If list IS_EMPTY, raise LIST_IS_EMPTY
  4106.       --|    Return NUMBER_OF_ELEMENTS
  4107.       --==============================================================
  4108.       
  4109.    begin
  4110.       if IS_EMPTY (ID) then
  4111.          raise LIST_IS_EMPTY;
  4112.       end if;
  4113.       return ID.NUMBER_OF_ELEMENTS;
  4114.       
  4115.    exception
  4116.       when LIST_IS_EMPTY  =>
  4117.          raise ;
  4118.       when others    =>
  4119.          raise UNEXPECTED_ERROR;
  4120.    end LAST_INDEX;
  4121.    
  4122.    --=======================================================================
  4123.    -- Move through the list
  4124.    --=======================================================================
  4125.    procedure ADVANCE (ID : in out LIST_ID) is
  4126.       
  4127.       --=========================== PDL ==============================
  4128.       --|ABSTRACT:
  4129.       --|    ADVANCE sets the current element to be the next element
  4130.       --|    if possible.
  4131.       --|DESIGN DESCRIPTION:
  4132.       --|    If list IS_EMPTY, raise LIST_IS_EMPTY
  4133.       --|    If at end of list (IS_END), raise ADVANCE_PAST_END_OF_LIST
  4134.       --|    Set CURRENT.PREVIOUS to CURRENT
  4135.       --|    Set CURRENT to CURRENT.NEXT
  4136.       --|    Increment CURRENT_INDEX
  4137.       --|NOTE:
  4138.       --|    ADVANCE will raise the ADVANCE_PAST_END_OF_LIST exception
  4139.       --|    if we are already at the end of the list and try to
  4140.       --|    advance from there.  ADVANCE will not raise any exception
  4141.       --|    if we were sitting on the last element and advanced to
  4142.       --|    the end_of_list state.  Hence, to use ADVANCE in coding,
  4143.       --|    a recommended algorithm is:
  4144.       --|        loop
  4145.       --|            advance(mylist);
  4146.       --|            exit when is_end(mylist);
  4147.       --|            null; -- do what you wish with the next element
  4148.       --|        end loop;
  4149.       --==============================================================
  4150.       
  4151.    begin
  4152.       if IS_EMPTY (ID) then
  4153.          raise LIST_IS_EMPTY;
  4154.       end if;
  4155.       if IS_END (ID) then
  4156.          raise ADVANCE_PAST_END_OF_LIST;
  4157.       end if;
  4158.       ID.CURRENT.PREVIOUS := ID.CURRENT;
  4159.       ID.CURRENT          := ID.CURRENT.NEXT;
  4160.       ID.CURRENT_INDEX    := ID.CURRENT_INDEX + 1;
  4161.       
  4162.    exception
  4163.       when LIST_IS_EMPTY  | ADVANCE_PAST_END_OF_LIST    =>
  4164.          raise ;
  4165.       when others    =>
  4166.          raise UNEXPECTED_ERROR;
  4167.    end ADVANCE;
  4168.    
  4169.    procedure BACKUP (ID : in out LIST_ID) is
  4170.       
  4171.       --=========================== PDL ==============================
  4172.       --|ABSTRACT:
  4173.       --|    BACKUP sets the current element to be the previous element
  4174.       --|    if possible.
  4175.       --|DESIGN DESCRIPTION:
  4176.       --|    If list IS_EMPTY, raise LIST_IS_EMPTY
  4177.       --|    If at front of list (IS_FIRST), raise
  4178.       --|      BACKUP_BEFORE_BEGINNING_OF_LIST
  4179.       --|    Set CURRENT.PREVIOUS to CURRENT.PREVIOUS.PREVIOUS
  4180.       --|    Set CURRENT.NEXT to CURRENT
  4181.       --|    Set CURRENT to CURRENT.PREVIOUS
  4182.       --|    Decrement CURRENT_INDEX
  4183.       --|NOTE:
  4184.       --|    BACKUP will raise the BACKUP_BEFORE_BEGINNING_OF_LIST 
  4185.       --|    exception if we are already at the start of the list and try 
  4186.       --|    to backup from there.  Hence, to use BACKUP in coding,
  4187.       --|    a recommended algorithm is:
  4188.       --|        loop
  4189.       --|            null; -- do what you wish with the next element
  4190.       --|            exit when is_first(mylist);
  4191.       --|            backup(mylist);
  4192.       --|        end loop;
  4193.       --==============================================================
  4194.       
  4195.    begin
  4196.       if IS_EMPTY (ID) then
  4197.          raise LIST_IS_EMPTY;
  4198.       end if;
  4199.       if IS_FIRST (ID) then
  4200.          raise BACKUP_BEFORE_BEGINNING_OF_LIST;
  4201.       end if;
  4202.       ID.CURRENT.PREVIOUS := ID.CURRENT.PREVIOUS.PREVIOUS;
  4203.       ID.CURRENT.NEXT     := ID.CURRENT;
  4204.       ID.CURRENT          := ID.CURRENT.PREVIOUS;
  4205.       ID.CURRENT_INDEX    := ID.CURRENT_INDEX - 1;
  4206.       
  4207.    exception
  4208.       when LIST_IS_EMPTY  | BACKUP_BEFORE_BEGINNING_OF_LIST  =>
  4209.          raise ;
  4210.       when others    =>
  4211.          raise UNEXPECTED_ERROR;
  4212.    end BACKUP;
  4213.    
  4214.    --=======================================================================
  4215.    -- Test the state of the list and the current element
  4216.    --=======================================================================
  4217.    function IS_EMPTY (ID : in LIST_ID) return BOOLEAN is
  4218.       
  4219.       --=========================== PDL ==============================
  4220.       --|ABSTRACT:
  4221.       --|    IS_EMPTY returns TRUE if the list is empty; FALSE otherwise.
  4222.       --|DESIGN DESCRIPTION:
  4223.       --|    If FIRST is NULL, return TRUE, else return FALSE
  4224.       --==============================================================
  4225.       
  4226.    begin
  4227.       return ID.FIRST = null;
  4228.    end IS_EMPTY;
  4229.    
  4230.    function IS_END (ID : in LIST_ID) return BOOLEAN is
  4231.       
  4232.       --=========================== PDL ==============================
  4233.       --|ABSTRACT:
  4234.       --|    IS_END returns TRUE if we are past the last element of the
  4235.       --|    list; FALSE otherwise.
  4236.       --|DESIGN DESCRIPTION:
  4237.       --|    If CURRENT is NULL, return TRUE, else return FALSE
  4238.       --==============================================================
  4239.       
  4240.    begin
  4241.       return ID.CURRENT = null;
  4242.    end IS_END;
  4243.    
  4244.    function IS_FIRST (ID : in LIST_ID) return BOOLEAN is
  4245.       
  4246.       --=========================== PDL ==============================
  4247.       --|ABSTRACT:
  4248.       --|    IS_FIRST returns TRUE if we are the first element of the
  4249.       --|    list; FALSE otherwise.
  4250.       --|DESIGN DESCRIPTION:
  4251.       --|    If CURRENT_INDEX is 1, return TRUE, else return FALSE
  4252.       --==============================================================
  4253.       
  4254.    begin
  4255.       return ID.CURRENT_INDEX = 1;
  4256.    end IS_FIRST;
  4257.    
  4258.    --=======================================================================
  4259.    -- Add elements to the list
  4260.    --=======================================================================
  4261.    procedure START_LIST (ID      : in out LIST_ID;
  4262.                          ELEMENT : ELEMENT_OBJECT) is
  4263.       
  4264.       --=========================== PDL ==============================
  4265.       --|ABSTRACT:
  4266.       --|    START_LIST creates a new list with 1 element.
  4267.       --|DESIGN DESCRIPTION:
  4268.       --|    Create NEW_ELEMENT (may raise DYNAMIC_MEMORY_ALLOCATION_PROBLEM)
  4269.       --|    Set FIRST to NEW_ELEMENT
  4270.       --|    Set LAST to NEW_ELEMENT
  4271.       --|    Set CURRENT to NEW_ELEMENT
  4272.       --|    Set NUMBER_OF_ELEMENTS to 1
  4273.       --|    Set CURRENT_INDEX to 1
  4274.       --==============================================================
  4275.       
  4276.       NEW_ELEMENT : ELEMENT_POINTER;
  4277.    begin
  4278.       ALLOCATE (ID, ELEMENT, NEW_ELEMENT);
  4279.       ID.FIRST              := NEW_ELEMENT;
  4280.       ID.LAST               := NEW_ELEMENT;
  4281.       ID.CURRENT            := NEW_ELEMENT;
  4282.       ID.NUMBER_OF_ELEMENTS := 1;
  4283.       ID.CURRENT_INDEX      := 1;
  4284.    end START_LIST;
  4285.    
  4286.    procedure APPEND_ELEMENT (ID      : in out LIST_ID;
  4287.                              ELEMENT : ELEMENT_OBJECT) is
  4288.       
  4289.       --=========================== PDL ==============================
  4290.       --|ABSTRACT:
  4291.       --|    APPEND_ELEMENT appends an element after the current
  4292.       --|    element in the linked list.  This new element is set
  4293.       --|    to be the current element.
  4294.       --|DESIGN DESCRIPTION:
  4295.       --|    If list IS_EMPTY
  4296.       --|        Call START_LIST
  4297.       --|    Else
  4298.       --|        Create NEW_ELEMENT (may raise
  4299.       --|          DYNAMIC_MEMORY_ALLOCATION_PROBLEM)
  4300.       --|        If at end of list (CURRENT = LAST or IS_END)
  4301.       --|            Set NEW_ELEMENT.PREVIOUS to LAST (NEW_ELEMENT.NEXT is
  4302.       --|              already NULL)
  4303.       --|            Set LAST.NEXT to NEW_ELEMENT
  4304.       --|            Set LAST to NEW_ELEMENT
  4305.       --|            Set CURRENT_INDEX to NUMBER_OF_ELEMENTS + 1
  4306.       --|        Else
  4307.       --|            Set NEW_ELEMENT.NEXT to CURRENT.NEXT
  4308.       --|            Set NEW_ELEMENT.PREVIOUS to CURRENT
  4309.       --|            Set CURRENT.NEXT.PREVIOUS to NEW_ELEMENT
  4310.       --|            Set CURRENT.NEXT to NEW_ELEMENT
  4311.       --|            Increment CURRENT_INDEX
  4312.       --|        End if
  4313.       --|        Set CURRENT to NEW_ELEMENT
  4314.       --|        Increment NUMBER_OF_ELEMENTS
  4315.       --|    End if
  4316.       --==============================================================
  4317.       
  4318.       NEW_ELEMENT : ELEMENT_POINTER;
  4319.    begin
  4320.       if IS_EMPTY (ID) then
  4321.          START_LIST (ID, ELEMENT);
  4322.       else
  4323.          ALLOCATE (ID, ELEMENT, NEW_ELEMENT);
  4324.          if ID.CURRENT = ID.LAST or IS_END (ID) then
  4325.             NEW_ELEMENT.PREVIOUS := ID.LAST;
  4326.             ID.LAST.NEXT         := NEW_ELEMENT;
  4327.             ID.LAST              := NEW_ELEMENT;
  4328.             ID.CURRENT_INDEX     := ID.NUMBER_OF_ELEMENTS + 1;
  4329.          else
  4330.             NEW_ELEMENT.NEXT         := ID.CURRENT.NEXT;
  4331.             NEW_ELEMENT.PREVIOUS     := ID.CURRENT;
  4332.             ID.CURRENT.NEXT.PREVIOUS := NEW_ELEMENT;
  4333.             ID.CURRENT.NEXT          := NEW_ELEMENT;
  4334.             ID.CURRENT_INDEX         := ID.CURRENT_INDEX + 1;
  4335.          end if;
  4336.          ID.CURRENT            := NEW_ELEMENT;
  4337.          ID.NUMBER_OF_ELEMENTS := ID.NUMBER_OF_ELEMENTS + 1;
  4338.       end if;
  4339.       
  4340.    exception
  4341.       when DYNAMIC_MEMORY_ALLOCATION_PROBLEM  =>
  4342.          raise ;
  4343.       when others    =>
  4344.          raise UNEXPECTED_ERROR;
  4345.    end APPEND_ELEMENT;
  4346.    
  4347.    procedure INSERT_ELEMENT (ID      : in out LIST_ID;
  4348.                              ELEMENT : ELEMENT_OBJECT) is
  4349.       
  4350.       --=========================== PDL ==============================
  4351.       --|ABSTRACT:
  4352.       --|    INSERT_ELEMENT inserts an element before the current
  4353.       --|    element in the linked list.
  4354.       --|DESIGN DESCRIPTION:
  4355.       --|    If list IS_EMPTY
  4356.       --|        Call START_LIST
  4357.       --|    Else
  4358.       --|        Create NEW_ELEMENT (may raise
  4359.       --|          DYNAMIC_MEMORY_ALLOCATION_PROBLEM)
  4360.       --|        If at front of list (IS_FIRST)
  4361.       --|            Set NEW_ELEMENT.NEXT to FIRST
  4362.       --|            Set FIRST.PREVIOUS to NEW_ELEMENT
  4363.       --|            Set FIRST to NEW_ELEMENT
  4364.       --|        ElsIf at end of list (IS_END)
  4365.       --|            Set NEW_ELEMENT.PREVIOUS to LAST (NEW_ELEMENT.NEXT is
  4366.       --|              already NULL)
  4367.       --|            Set LAST.NEXT to NEW_ELEMENT
  4368.       --|            Set LAST to NEW_ELEMENT
  4369.       --|        Else
  4370.       --|            Set NEW_ELEMENT.NEXT to CURRENT
  4371.       --|            Set NEW_ELEMENT.PREVIOUS to CURRENT.PREVIOUS
  4372.       --|            Set CURRENT.PREVIOUS.NEXT to NEW_ELEMENT
  4373.       --|            Set CURRENT.PREVIOUS to NEW_ELEMENT
  4374.       --|        End if
  4375.       --|        Increment CURRENT_INDEX
  4376.       --|        Increment NUMBER_OF_ELEMENTS
  4377.       --|    End if
  4378.       --==============================================================
  4379.       
  4380.       NEW_ELEMENT : ELEMENT_POINTER;
  4381.    begin
  4382.       if IS_EMPTY (ID) then
  4383.          START_LIST (ID, ELEMENT);
  4384.       else
  4385.          ALLOCATE (ID, ELEMENT, NEW_ELEMENT);
  4386.          if IS_FIRST (ID) then
  4387.             NEW_ELEMENT.NEXT  := ID.FIRST;
  4388.             ID.FIRST.PREVIOUS := NEW_ELEMENT;
  4389.             ID.FIRST          := NEW_ELEMENT;
  4390.          elsif IS_END (ID) then
  4391.             NEW_ELEMENT.PREVIOUS := ID.LAST;
  4392.             ID.LAST.NEXT         := NEW_ELEMENT;
  4393.             ID.LAST              := NEW_ELEMENT;
  4394.          else
  4395.             NEW_ELEMENT.NEXT         := ID.CURRENT;
  4396.             NEW_ELEMENT.PREVIOUS     := ID.CURRENT.PREVIOUS;
  4397.             ID.CURRENT.PREVIOUS.NEXT := NEW_ELEMENT;
  4398.             ID.CURRENT.PREVIOUS      := NEW_ELEMENT;
  4399.          end if;
  4400.          ID.CURRENT_INDEX      := ID.CURRENT_INDEX + 1;
  4401.          ID.NUMBER_OF_ELEMENTS := ID.NUMBER_OF_ELEMENTS + 1;
  4402.       end if;
  4403.       
  4404.    exception
  4405.       when DYNAMIC_MEMORY_ALLOCATION_PROBLEM  =>
  4406.          raise ;
  4407.       when others    =>
  4408.          raise UNEXPECTED_ERROR;
  4409.    end INSERT_ELEMENT;
  4410.    
  4411.    --=======================================================================
  4412.    -- Delete elements from the list
  4413.    --=======================================================================
  4414.    procedure DELETE_ELEMENT (ID : in out LIST_ID) is
  4415.       
  4416.       --=========================== PDL ==============================
  4417.       --|ABSTRACT:
  4418.       --|    DELETE_ELEMENT deletes the current element in the linked
  4419.       --|    list.  The next element is made the current element.
  4420.       --|DESIGN DESCRIPTION:
  4421.       --|    If list IS_EMPTY raise LIST_IS_EMPTY
  4422.       --|    If list IS_END raise ADVANCE_PAST_END_OF_LIST
  4423.       --|    If CURRENT is FIRST
  4424.       --|        Set FIRST to CURRENT.NEXT
  4425.       --|    Else
  4426.       --|        Set NEXT of CURRENT.PREVIOUS to CURRENT.NEXT
  4427.       --|    End if
  4428.       --|    If CURRENT is LAST
  4429.       --|        Set LAST to CURRENT.PREVIOUS
  4430.       --|        Free up CURRENT
  4431.       --|        Set CURRENT to NULL
  4432.       --|    Else
  4433.       --|        Set PREVIOUS of CURRENT.NEXT to CURRENT.PREVIOUS
  4434.       --|        Free up CURRENT
  4435.       --|        Set CURRENT to CURRENT.NEXT
  4436.       --|    End if
  4437.       --|    Decrement NUMBER_OF_ELEMENTS
  4438.       --==============================================================
  4439.       
  4440.       SAVE : ELEMENT_POINTER;
  4441.       
  4442.    begin
  4443.       if IS_EMPTY (ID) then
  4444.          raise LIST_IS_EMPTY;
  4445.       end if;
  4446.       if IS_END (ID) then
  4447.          raise ADVANCE_PAST_END_OF_LIST;
  4448.       end if;
  4449.       if ID.CURRENT = ID.FIRST then
  4450.          ID.FIRST := ID.CURRENT.NEXT;
  4451.       else
  4452.          ID.CURRENT.PREVIOUS.NEXT := ID.CURRENT.NEXT;
  4453.       end if;
  4454.       if ID.CURRENT = ID.LAST then
  4455.          ID.LAST    := ID.CURRENT.PREVIOUS;
  4456.          ADD_TO_FREE (ID, ID.CURRENT);
  4457.          ID.CURRENT := null;
  4458.       else
  4459.          ID.CURRENT.NEXT.PREVIOUS := ID.CURRENT.PREVIOUS;
  4460.          SAVE                     := ID.CURRENT.NEXT;
  4461.          ADD_TO_FREE (ID, ID.CURRENT);
  4462.          ID.CURRENT               := SAVE;
  4463.       end if;
  4464.       ID.NUMBER_OF_ELEMENTS := ID.NUMBER_OF_ELEMENTS - 1;
  4465.       
  4466.    exception
  4467.       when LIST_IS_EMPTY  | ADVANCE_PAST_END_OF_LIST    =>
  4468.          raise ;
  4469.       when others    =>
  4470.          raise UNEXPECTED_ERROR;
  4471.    end DELETE_ELEMENT;
  4472.    
  4473. end DOUBLY_LINKED_LIST;
  4474. --::::::::::
  4475. --dyn.bdy
  4476. --::::::::::
  4477. package body DYN is
  4478.            
  4479.   procedure CLEAR(DSTR: in out DYN_STRING) is
  4480.     
  4481.     begin
  4482.       DSTR.SIZE := 0;
  4483.     end CLEAR;
  4484.  
  4485.   function D_STRING(CHAR: CHARACTER)  return DYN_STRING is
  4486.           
  4487.       DS : DYN_STRING;
  4488.     
  4489.     begin
  4490.       DS.SIZE     := 1;
  4491.       DS.DATA(1)  := CHAR;
  4492.       return DS;
  4493.     end D_STRING;
  4494.   
  4495.   function D_STRING(STR : STRING   )  return DYN_STRING is
  4496.           
  4497.       DS : DYN_STRING;
  4498.     
  4499.     begin
  4500.       DS.SIZE                   := STR'LENGTH;
  4501.       DS.DATA(1..DS.SIZE)       := STR;
  4502.       return DS;
  4503.     end D_STRING;
  4504.   
  4505.   function CHAR(DSTR  : DYN_STRING;
  4506.                 POSIT : POSITIVE := 1) return CHARACTER is
  4507.     
  4508.     begin
  4509.       if POSIT > DSTR.SIZE then 
  4510.         raise STRING_TOO_SHORT;
  4511.       else 
  4512.         return DSTR.DATA(POSIT);
  4513.       end if;
  4514.     end CHAR;
  4515.   
  4516.   function STR (DSTR: DYN_STRING) return STRING is
  4517.     
  4518.     begin
  4519.       return DSTR.DATA(1..DSTR.SIZE);
  4520.     end STR;
  4521.   
  4522.   function LENGTH(DSTR: DYN_STRING) return NATURAL is
  4523.     
  4524.     begin
  4525.       return DSTR.SIZE;
  4526.     end LENGTH;
  4527.   
  4528.     begin --(DYN)
  4529.       null;
  4530.     exception
  4531.       when others => 
  4532.         raise;
  4533.  
  4534.     end DYN;
  4535.